2

我正在使用doctrine-mongodb-odm-1.0.0-BETA10并尝试提供一些基于事件运行\InitialDocument时的自定义逻辑。preUpdate

假设\InitialDocument获得了一些状态,该状态必须作为 new 的初始状态\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让我认为这不是正确的方法。请给我适当的建议。谢谢。

4

1 回答 1

5

我在这里为您的用例创建了一个测试用例。从您的问题中的代码中脱颖而出的一件事是,您没有recomputeSingleDocumentChangeSet()在生命周期回调期间调用您正在修改的文档,如preUpdate文档中所述。但即使使用该调用,也不会插入新文档。这是因为 UnitOfWork在插入和 upsert之后执行更新。完整的顺序可以在UnitOfWork 的commit()方法中看到:

  • 文档更新
  • 文档插入
  • 文件更新
  • 额外更新(由持久化类在内部安排)
  • 集合删除
  • 收藏更新
  • 文件删除

preUpdate事件被调度时,新文档的 upserts/inserts 已经发生。即使调用了recomputeSingleDocumentChangeSet(),您最终也会安排要插入的文档,但 UnitOfWork 会忽略这一点,并最终在清除此处的所有调度队列时取消设置。

虽然一个简单的解决方案是让 ODM 在处理更新后检查额外的插入,但在某些情况下这可能会导致无限循环。UnitOfWork 订购早于我在项目上的工作,但在构思最初的实现时,我可能担心循环的风险。

作为一种变通方法,您可能希望让侦听器转储要插入到其他容器(或侦听器本身)的新文档,然后在事后检查要持久/刷新的其他文档。

于 2014-05-29T15:29:26.670 回答