2012-06-18 100 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(); 

它的几行,但没有克隆或任何其他类型的魔法。直接告诉学说做一个该死的更新!希望这可以帮助。

注意:在我的情况下,它是$元素没有被设置。我取消了之前查询中的所有匹配,并且原则只是没有看到它,因此拒绝更新元素。

相关问题