Symfony2 将实体对象序列化为会话

Posted

技术标签:

【中文标题】Symfony2 将实体对象序列化为会话【英文标题】:Symfony2 serialize entity object to session 【发布时间】:2012-03-12 04:37:51 【问题描述】:

我想将我的一个实体对象保存到会话中,但在执行此操作时,出现以下两个错误:

例外: Symfony\Bundle\FrameworkBundle\DataCollector\RequestDataCollector::serialize() 必须返回一个字符串或NULL

ErrorException: 注意:serialize(): "id" 作为成员返回 来自 __sleep() 的变量,但不存在于 /var/www/clients/client71/web256/web/_dev_fd/kkupon/vendor/symfony/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php 第 29 行

我的代码是这样的:

$offer = $this->getEntityManager()->getRepository('KkuponMainBundle:Offer')->find($offer_id);
$request->getSession()->set('offer', $offer);

我怎样才能做到正确?

谢谢。

更新 在 Rowgm 的帮助下,我可以通过设置受保护而不是私有的属性来解决这个问题。我唯一的问题是在 读取 会话中的实体之后 EntityManager 不知道它,如果我将对象(来自会话)添加到另一个对象(它们之间存在 OneToMany 关系) ,它不会工作。

<?php
$offer = $this->get('session')->get('offer');
$coupon = new Coupon();
$coupon->setOffer($offer);
$this->em->persist($coupon);
$this->em->flush();

这会引发错误,因为根据 EntityManager 的说法,优惠券有一个对象属性不在数据库中(实际上它在数据库中,我从数据库中放入会话)。

<?php
$offer = $this->get('session')->get('offer');
echo $this->em->getUnitOfWork()->isInIdentityMap($offer) ? "yes":"no"; //result: no

一种解决方案可以是: $offer = $this-&gt;em-&gt;merge($offer);

但这似乎不是最好的。我希望我的 EntityManager 能够感知存储在会话中的实体对象,而无需每次都告诉它。 有什么想法吗?

【问题讨论】:

【参考方案1】:

不推荐序列化实体,您可以在Doctrine-documentation 中看到。您应该实现Serializable-interface 并手动序列化/反序列化实体数据。

【讨论】:

序列化我的实体会有问题,因为它包含许多外来对象,甚至是外来实体的 ArrayCollections。有什么比只存储 id 并在每次需要时从数据库中检索对象更好的主意? 从您的异常中可以看出,当将其放入会话时,它将被序列化,这就是导致错误的原因。但是正如您所说,由于对象的复杂性,您可能应该存储 id 并再次从数据库中检索对象。可能使用某种对象缓存也可以,但我不确定。 谢谢,我只存储id。【参考方案2】:

您可以通过覆盖 __sleep 方法来排除不需要的字段:

public function __sleep() 

    // these are field names to be serialized, others will be excluded
    // but note that you have to fill other field values by your own
    return array('id', 'username', 'password', 'salt');

【讨论】:

【参考方案3】:

您可以通过将其所有属性和关系从 private 设置为 protected 来序列化任何实体。

您可能会遇到 symfony2 的常见问题,即使您已将所有属性设置为受保护:您必须重新生成已更改的实体的代理。为此,只需清除缓存即可。对于开发环境

app/console cache:clear

正如你所说,即使“它包含许多外来对象,甚至是外来实体的 ArrayCollections”,它也能正常工作。

【讨论】:

想一想:如果您存储所有实体,您将在会话数据中存储一个大对象。对于您的开发环境,这不是问题。但是如果你有很多用户,那就是资源的浪费。解决方案非常简单:存储对象的 id 并使用存储库的 find() 方法来检索对象。最后,还是一样的。 嗯,我想,框架应该为我提供这个功能。所以我不必每次想使用实体时都调用 find 函数。

以上是关于Symfony2 将实体对象序列化为会话的主要内容,如果未能解决你的问题,请参考以下文章

在将实体框架对象图序列化为 Json 时防止 ***Exception

如何将具有嵌套属性的 JSON 对象反序列化为 Symfony 实体?

Symfony - 将 json 反序列化为实体数组

如何将地理位置点数据反序列化为 Java 实体?

EF 将实体序列化为包含相关实体的 json 创建一个循环

REST:如何以“浅”的方式将 java 对象序列化为 JSON?