在学说-mongodb 中的 preUpdate 事件时创建/保留新文档
Posted
技术标签:
【中文标题】在学说-mongodb 中的 preUpdate 事件时创建/保留新文档【英文标题】:Creating/persisting new document while preUpdate event in doctrine-mongodb 【发布时间】:2014-07-18 15:26:27 【问题描述】:我正在使用doctrine-mongodb-odm-1.0.0-BETA10
并尝试在preUpdate
事件运行时提供一些基于\InitialDocument
的自定义逻辑。
假设\InitialDocument
获得了一些状态,该状态必须作为新\StateDocument
的初始状态。我正在做这样的事情:
class InitDocListener implements \Doctrine\Common\EventSubscriber
public function getSubscribedEvents()
return [
Events::preUpdate
];
public function preUpdate($args)
$document = $args->getDocument();
if($document instanceOf InitialDocument && $document->getState() == 'mine')
$stateDocument = new \StateDocument();
$stateDocument->setInitDocument($document);
$args->getDocumentManager()->persist($stateDocument);
//no flush cause recursion happens
prePersist
事件由\StateDocument
发生,但它不会在数据库中保留新文档。并且 postPersist
事件将永远不会被触发。
还有一些自定义逻辑,但都在事件范围内。在某些时候,逻辑可能会抛出一个异常,该异常必须停止 InitialDocument
的更新事件,因此 InitialDocument
状态取决于业务范围内的 \StateDocument
创建过程。
我该如何解决这个问题? preFlush
在 changeSet 重新计算之前运行的事件不能确定 InitialDocument
实例。因此,在preFlush
上“搜索”更新是一种技巧,让我认为这不是正确的方法。请给我适当的建议。谢谢。
【问题讨论】:
【参考方案1】:我为您的用例 here 创建了一个测试用例。从您的问题中的代码中脱颖而出的一件事是,您没有在生命周期回调期间对您正在修改的文档调用recomputeSingleDocumentChangeSet()
,正如preUpdate
documentation 中提到的那样。但即使使用该调用,也不会插入新文档。这是因为 UnitOfWork 在插入和更新插入之后执行更新。完整订单可见UnitOfWork's commit()
method:
当preUpdate
事件被调度时,新文档的更新插入/插入已经发生。即使调用recomputeSingleDocumentChangeSet()
,您最终也会安排要插入的文档,但UnitOfWork 会忽略这一点,并最终在清除所有计划队列here 时取消设置。
虽然一个简单的解决方案是让 ODM 在处理更新后检查其他插入,但在某些情况下这可能会导致无限循环。 UnitOfWork 排序早于我在项目上的工作,但我在构思最初的实现时可能会担心循环的风险。
作为一种变通方法,您可能希望让侦听器转储要插入到其他容器(或侦听器本身)的新文档,然后在事后检查要持久/刷新的其他文档。
【讨论】:
谢谢。昨天我在 UnitOfWork 上玩了一段时间,得出了类似的结论。您刚刚确认了在这种情况下我们需要在其他容器中处理插入文档的假设。问题在于preUpdate
事件导致新文档的 MANAGED 状态在当时持续存在,并且在提交 //Clear up
其 upsertions(和其他内容)之后持续存在。文档保持已知并声明为已管理,但在该文档的新持久/刷新期间会导致错误。
所以我尝试包装 flush()
来处理自己的自定义事件 afterCommit
(在 clear up
之后)并再次添加 scheduleForUpsert 以防止执行 persist()
。但它没有用。现在我正试图完全放弃preUdpate
,转而支持我的afterCommit
。如果问题将被批准进入 GitHub,将带来一些(故障转移?)测试。
毕竟。决定放弃 preUpdate
事件以支持包装刷新并实现 afterCommit
事件并在新的文档持久性应用程序逻辑发出失败时具有回滚行为。队列: 1. preUpdate
验证初始文档并为回滚进行更改集。 2.afterUpdate
将文件附加到updated_docs collection
。 3 afterCommit
事件触发基于updated_docs_collection
创建新文档并刷新它们或在失败时回滚更新的文档。不是一个好的实现,但现在可以工作。以上是关于在学说-mongodb 中的 preUpdate 事件时创建/保留新文档的主要内容,如果未能解决你的问题,请参考以下文章
SonataAdminBundle 中的 Symfony preUpdate 事件
hibernate/JPA 中的 @PreUpdate 和 @Prepersist(使用会话)