问题描述
我正在尝试检测 onFlush
事件中多对多关系的变化.
I'm trying to detect changes in a many-to-many relation in an onFlush
event.
如果将新实体添加到关系或更新关系(始终保留一个元素),我可以使用 $unitOfWork->getScheduledCollectionUpdates()
检测更改,然后检查 getInsertDiff()
或 getDeleteDiff()
.到目前为止一切顺利.
If new entities are added to the relation or the relation is updated (always keeping an element), I can detect changes using $unitOfWork->getScheduledCollectionUpdates()
and then check for getInsertDiff()
or getDeleteDiff()
. So far so good.
当我从关系中取出所有实体时,问题出现了:之前有两个相关实体,但现在有 NO 个相关实体."
The problem comes when I take all the entities out of the relation: "There were two related entities before but there are NO related entities now."
当关系为空时,我可以访问 $unitOfWork->getScheduledCollectionDeletions()
,但无法知道删除了哪些实体:
When the relation is left empty I can access $unitOfWork->getScheduledCollectionDeletions()
, but there is no way of knowing which entities were deleted:
- 此集合的
getDeleteDiff()
没有任何意义.getSnapshot()
没有告诉我之前有哪些实体
getDeleteDiff()
for this collections doesn't tell anything.getSnapshot()
doesn't tell me which entities were there before
我应该如何知道从多对多关系中取出了哪些实体?
How should I know which entities were taken out of the many-to-many relation?
我添加了一个完整实现的要点:除了 $uow->getScheduledCollectionDeletions()
(第 101 行)
I've added a Gist with the full implementation: everything works ok (it may need some optimization) except $uow->getScheduledCollectionDeletions()
(line 101)
https://gist.github.com/eillarra/5127606
推荐答案
这个问题的原因是双重的:
1) 当在 DoctrineORMPersistentCollection
上调用方法 clear()
时,它将:
1) When the method clear()
is called on a DoctrineORMPersistentCollection
, it will:
- 清除其内部实体集合.
- 在
DoctrineORMUnitOfWork
上调用scheduleCollectionDelection()
. - 为自己拍摄一张新的快照.
第二个原因是您的收藏出现在 $uow->getScheduledCollectionDeletions()
中(而不是在 $uow->getScheduledCollectionUpdates()
中).第 3 点是您无法确定收藏品在被清除之前包含哪些内容的原因.
Number 2 is the reason your collection shows up in $uow->getScheduledCollectionDeletions()
(and not in $uow->getScheduledCollectionUpdates()
). Number 3 is the reason why you cannot determine what was in the collection before it was cleared.
2) 当使用 Symfony2 表单组件时,特别是 ChoiceType
或 CollectionType
类型与选项 multiple
组合时,当 所有 实体应该从集合中移除时,将调用 clear()
方法.
2) When using the Symfony2 Form component, specifically the ChoiceType
or CollectionType
types in combination with the option multiple
, that clear()
method will get called when all entities should be removed from the collection.
这是由于在此处添加的 MergeDoctrineCollectionListener
造成的:https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php#L55
This is due to the MergeDoctrineCollectionListener
which is added here:https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php#L55
这是作为优化完成的:以这种方式清除集合更快,而不是检查应该从中删除哪些实体.
This is done as optimization: It's faster to clear a collection this way, in stead of checking which entities should be removed from it.
我能想到两个可能的解决方案:
1) 创建一个分支 symfony/symfony
并实现一个选项以便不添加 MergeDoctrineCollectionListener
.也许像 no_clear
之类的东西可以防止添加侦听器.这不会引入 BC 中断,并且会解决您的问题,因为当应该删除 所有 实体时,不会调用集合的 clear()
方法.
1) Create a fork symfony/symfony
and implement an option in order to not add the MergeDoctrineCollectionListener
. Maybe something like no_clear
to prevent the listener from being added. This won't introduce a BC break and would solve your problem because the clear()
method of a collection won't get called when all entities should be removed.
2) 重新设计您的计数器:也许还可以监听 OnLoad
事件,该事件可以在从数据库中获取集合时计算集合中的实体数量.这样,您的 OnFlush
侦听器可以使用该数字来了解在清除集合时从集合中删除了多少实体.
2) Redesign your counter: Maybe also listen to the OnLoad
event which can count the amount of entities in the collection at the time it's fetched from the db. That way your OnFlush
listener can use that number to know how many entities where removed from the collection when it was cleared.
这篇关于在 Doctrine 2(和 Symfony)中正确使用 $unitOfWork->getScheduledCollectionDeletions() 是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!