如何使用实体管理器管理反序列化的实体?

时间:2012-06-26 18:09:26

标签: serialization symfony doctrine-orm deserialization

我正在使用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 < / strong>对象。

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

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

  

{“id”:null,“items”:[{“id”:1,“金额”:100},{“id”:2,“金额”:200}]}

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

2 个答案:

答案 0 :(得分:6)

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

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

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

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

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

答案 1 :(得分:2)

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

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

请检查this comment以了解其他好处。 here就是如何启用它的。