2012-06-18 41 views
9

我有數組類型字段主義實體:如何強制Doctrine更新數組類型字段?

/** 
* @ORM\Table() 
*/ 
class MyEntity 
{ 
    (...) 

    /** 
    * @var array $items 
    * 
    * @ORM\Column(type="array") 
    */ 
    private $items; 

    /** 
    * @param SomeItem $item 
    */ 
    public function addItem(SomeItem $item) 
    { 
     $this->items[] = $item; 
    } 

    (...) 
} 

如果我添加元素的數組,該代碼工作正常:

$myEntityObject->addItems(new SomeItem()); 
$EntityManager->persist($myEntityObject); 
$EntityManager->flush(); 

$myEntityObject保存與正確數據的數據庫(陣列被序列化,並在查詢數據庫時反序列化)。

不幸的是,當我改變數組中的一個對象而不更改數組的大小時,如果我試圖保存對數據庫的更改,則Doctrine不執行任何操作。

$items = $myEntityObject->getItems(); 
$items[0]->setSomething(123); 
$myEntityObject->setItems($items); 
$EntityManager->persist($myEntityObject); 
$EntityManager->flush(); 
print_r($myEntityObject); 

雖然,在改變對象的數據代碼顯示的最後一行print_r,原則不知道什麼東西該數組內改變,如果數組的大小沒有改變。有什麼方法可以強制Doctrine保存在該字段中所做的更改(或輕輕通知它需要保存的該字段中的更改)?

回答

21

學說使用相同的運算符(===)來比較舊值和新值之間的變化。在具有不同數據的相同對象(或對象數組)上使用的運算符總是返回true。還有另外一種方法可以解決這個問題,你可以克隆需要改變的對象。

$items = $myEntityObject->getItems(); 
$items[0] = clone $items[0]; 
$items[0]->setSomething(123); 
$myEntityObject->setItems($items); 

// ... 

或改變setItems()方法(我們需要克隆只有一個對象堅持整個陣列)

public function setItems(array $items) 
{ 
    if (!empty($items) && $items === $this->items) { 
     reset($items); 
     $items[key($items)] = clone current($items); 
    } 
    $this->items = $items; 
} 

關於第二個問題:

是否有人知道如何保存默認跟蹤其他字段的策略,並使用NotifyPropertyChanged僅用於存儲數組的字段?

您無法爲一個字段設置跟蹤策略。

+0

我正在嘗試此操作,如果此操作將盡快爲您提供獎勵。你的回答聽起來很棒!非常感謝@Vladim Ashikhman – Mick

+0

令人驚歎!我只能在2小時內歸功賞金,但這都是你的。我在這花了很多時間,說實話,我不是唯一的一個。邏輯很漂亮。你真棒!請參考這篇文章[這個問題](http://stackoverflow.com/questions/13227658/doctrine-does-not-update-a-simple-array-type-field/13232142#13232142)。事實證明,這是一個非常相似的問題。做得好! – Mick

+1

我已經改變了setMethod()了一下,它現在可以工作,如果你改變數組的光標。 –

1

就在文檔找到一種方式來解決我的問題:

http://docs.doctrine-project.org/en/latest/reference/change-tracking-policies.html

它需要大量的代碼更改的,但它的作品。有人知道如何爲其他字段保留默認的跟蹤策略,並只爲存儲數組的字段使用NotifyPropertyChanged?

+0

您可以使用'$ uow-> propertyChanged($ entity,$ propertyName,$ oldValue,$ newValue)''。例如在'preUpdate'回調中。 – origaminal

1

我在我的代碼中解決這個問題的方式是使用createQueryBuilder並創建更新查詢。這樣的學說沒有說不:)

所以我從這個

$em   = $this->getDoctrine()->getManager(); 
$matchEntity = $em->getReference('MyBundleBundle:Match', $match_id); 


$matchEntity->setElement($element); 
$matchEntity->setTeamHomeColour($data['team_a_colour']); 
$matchEntity->setTeamAwayColour($data['team_b_colour']); 

來到這的方式:代碼

$repository = $this->getDoctrine()->getRepository('MyBundleBundle:Match'); 
$query  = $repository->createQueryBuilder('u') 
    ->update() 
    ->set('u.element', ':element') 
    ->set('u.teamHomeColour', ':thomecolour') 
    ->set('u.teamAwayColour', ':tawaycolour') 
    ->where('u.matchId = :match') 

    ->setParameter('element', $element) 
    ->setParameter('thomecolour', $data['team_a_colour']) 
    ->setParameter('tawaycolour', $data['team_b_colour']) 
    ->setParameter('match', $matchEntity) 

    ->getQuery(); 

$query->execute(); 

它的幾行,但沒有克隆或任何其他類型的魔法。直接告訴學說做一個該死的更新!希望這可以幫助。

注意:在我的情況下,它是$元素沒有被設置。我取消了之前查詢中的所有匹配,並且原則只是沒有看到它,因此拒絕更新元素。