2

我正在使用 JMSSerializerBundle 将我的实体序列化为 json 并将 json 反序列化为实体,但我认为这个问题适用于任何反序列化技术。

例如,此架构:

class Order
{
    private $id;

    /**
     * @Serializer\Type("ArrayCollection<MyBundle\Entity\Order\Item>")
     * @ORM\OneToMany(targetEntity="\MyBundle\Entity\Order\Item", mappedBy="order", cascade={"persist"})
     */
    private $items;
}

class Item
{

    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="\MyBundle\Entity\Order", inversedBy="items")
     */
    private $order;

    /**
     * @var integer $amount
     * @Serializer\Type("integer")
     * @ORM\Column(name="amount", type="integer")
     */
    private $amount;

}

映射到这个 json:{"id":1,"items":[{"id":1,"amount":100}, {"id":2,"amount":200}]}并且相同的 json 被正确反序列化为MyBundle:Order类型的对象,该对象具有两个MyBundle:Order/Item对象的集合。

问题是,当我尝试持久化此对象时,会在数据库中创建新条目,而不是更新现有条目,而忽略 id。我如何告诉实体管理器这些对象应该更新,而不是创建?

更新。通常 EntityManager::merge 解决方案(如 DaveM 建议的那样)很好。但您只能合并现有对象。例如,如果您有一个 json 表示一个新的 Order 实体,该实体连接到现有的 Order\Item 实体

{"id":null,"items":[{"id":1,"amount":100}, {"id":2,"amount":200}]}

在这种情况下,您不能像这样合并 Order 对象: $em->merge($order)因为 order 是一个新实体,并且实体管理器将尝试查找 id = null 的 Order 对象,您最终将得到一个新的 Order 和空 items 数组。所以解决方案是循环 Order::$items 数组并单独合并每个项目。然后将创建一个新订单并将其与现有项目连接。

4

2 回答 2

6

您需要使用as 合并实体merge()上的方法EntityManager是指将实体合并到 EntityManager 的上下文中,以便它们可以再次被管理。为了将实体的状态合并到 EntityManager 中,请使用 EntityManager#merge($entity) 方法。传递的实体的状态将被合并到该实体的托管副本中,该副本随后将被返回。

$detachedEntity = unserialize($serializedEntity); 
$entity = $em->merge($detachedEntity);

另外请务必注意,当您想要序列化/反序列化实体时,您必须保护所有实体属性,而不是私有的。这样做的原因是,如果你序列化一个之前是代理实例的类,私有变量将不会被序列化,并且会抛出 PHP 通知。

更多信息可以在此处的学说文档中找到:

http://doctrine-orm.readthedocs.org/en/2.0.x/reference/working-with-objects.html#merging-entities

于 2012-06-26T19:11:11.650 回答
2

我知道这个问题已经存在三年了,但它误导我认为唯一的答案是使用合并操作。我想加两分钱:

JMSSerializerBundle 包含一个用于 Doctrine 实体的对象构造函数。当您启用此构造函数时,反序列化的实体是可以持久化的托管实体(使用$em->persist($entity))。

请查看此评论以了解其他好处。以下是启用它的方法。

于 2016-06-23T21:22:29.207 回答