2012-06-26 95 views
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的目的:訂單具有兩個MyBundle一個總彙:訂單/ Item對象。

問題是,當我試圖堅持這個對象時,在數據庫中創建了新的條目,而不是更新現有的,忽略了ID。我如何告訴實體經理這些對象應該更新,而不是創建?

更新。通常EntityManager :: merge解決方案(由DaveM建議)很好。但是你只能合併現有的對象。例如,如果您有一個代表連接到現有Order \ Item實體的新Order實體的json

{「id」:null,「items」:[{「id」:1,「amount 「:100},{」 ID 「:2,」 金額「:200}]}

在這種情況下,你不能只是合併Order對象是這樣的: $em->merge($order),因爲訂單是一個新的實體和實體經理將嘗試查找id = null的Order對象,並且您將以新的Order和空項目數組結束。所以解決方案是循環Order :: $ items數組並單獨合併每個項目。然後將創建一個新的訂單並與現有的物品連接。

回答

5

您需要使用EntityManager上的merge()方法,因爲合併實體是指將實體合併到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

3

我知道這個問題是三十歲了,但它誤導我唯一的答案是使用合併操作思考。我想添加我的兩分錢:

JMSSerializerBundle包含用於Doctrine實體的對象構造函數。當您啓用此構造函數時,反序列化實體是可以持久化的管理實體(使用$em->persist($entity))。

請檢查this comment瞭解其他好處。 和here是你如何啓用它。