我正在尝试检测onFlush
事件中多对多关系的变化。
如果新的实体被添加到关系中或者关系被更新(总是保留一个元素),我可以使用$unitOfWork->getScheduledCollectionUpdates()
检测变化,然后检查getInsertDiff()
或getDeleteDiff()
。
当我把所有实体从关系中取出时,问题就来了:* “以前有两个关联实体,但现在没有关联实体。"*
当关系为空时,我可以访问$unitOfWork->getScheduledCollectionDeletions()
,但无法知道哪些实体被删除了:
- 这个集合的
getDeleteDiff()
没有任何意义。
*getSnapshot()
不告诉我以前存在哪些实体
我如何知道哪些实体从多对多关系中删除?
我已经添加了一个完整实现的要点:除了$uow->getScheduledCollectionDeletions()
(第101行)之外,一切正常(可能需要一些优化)
https://gist.github.com/eillarra/5127606
3条答案
按热度按时间icnyk63a1#
此问题的原因有两个:
1)当在
Doctrine\ORM\PersistentCollection
上调用方法clear()
时,它将:1.清除其内部实体集合。
1.在
Doctrine\ORM\UnitOfWork
上调用scheduleCollectionDeletion()
。1.给自己拍一张新快照。
第二个原因是您的集合显示在
$uow->getScheduledCollectionDeletions()
中(而不是$uow->getScheduledCollectionUpdates()
中);第三个原因是您无法确定集合在被清除之前的内容。2)当使用Symfony 2表单组件时,特别是
ChoiceType
或CollectionType
类型与选项multiple
结合使用时,当应从集合中删除 * 所有 * 实体时,将调用clear()
方法。这是由于此处添加了
MergeDoctrineCollectionListener
:https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php#L55这是作为优化完成的:用这种方式清除集合比检查应该从集合中删除哪些实体要快。
我可以想到两个可能的解决方案:
1)创建一个fork
symfony/symfony
,并实现一个选项,以便 * 不 * 添加MergeDoctrineCollectionListener
。也许像no_clear
这样的东西可以防止添加侦听器。这不会引入BC中断,并会解决您的问题,因为当 * 所有 * 实体应该被删除时,集合的clear()
方法不会被调用。2)重新设计计数器:也许还可以监听
OnLoad
事件,该事件可以计算从数据库中获取集合时集合中的实体数量,这样,OnFlush
监听器就可以使用该数字来了解在清除集合时从集合中删除了多少实体。eqqqjvef2#
我发现如果将
'by_reference' => false,
选项设置为EntityType形式,则UnitOfWork会检测集合的更改。请参见OnFlush事件时UnitOfWork中的差异状态:'by_reference' => false
'by_reference' => true
tvmytwxo3#
如果最后一项被删除(比如在提交表单时),“getDeleteDiff”有时会变成空的,但实际上,项是存在的,解决方案是从数据库中获取原始数据。在我的示例中,我们使用集合的克隆来实现这一点。因此,原始集合保持不变,一切仍然有效。
关于这个问题,Github上有多个问题:
https://github.com/doctrine/orm/issues/2272
https://github.com/doctrine/orm/issues/4173