在一个巨大的数据集中,当删除一个文档时,我有时会出现不一致。Symfony2应用程序与Doctrine ODM和FosREST
$a = new Element();
$b = new Element();
$c = new List();
$c->addElement($a);
$c->addElement($b);
$em->persist($c);
此时保存操作完美
在99%的情况下,当稍后加载$c时,$a和$b仍然是有效的文档。但是有时删除$a或$b而不更新$c中的引用。
->此时,$c的下一次加载将失败,出现\Doctrine\ODM\MongoDB \DocumentNotFoundException
(消息类似于:无法找到标识符为"541417702798711d2900607c"的"MongoDB ODMProxies__CG__\App\Model\Element"文档。)
现在处理这个案子的最佳方法是什么?
我在考虑
- 捕获异常并检查它试图加载的引用是否在元素模型上
- fosRest中要检查的自定义异常处理程序
- 自定义存储库函数,并在那里检查所有内容是否仍然有效(+以某种方式存储缺少的元素)->但这会迫使我在任何情况下检查是否设置了"错误"
更新:文档之间的映射比我在这里描述的要复杂一些
- 首先,元素基本上是一个由鉴别器分隔的集合,其中只有一种类型的字段引用另一个文档(我现在称之为"树")
- 一棵树可以在成千上万的ElementTree中使用(包含一棵树的特定类型)
- 有时Tree的可以被删除(这已经是一个运行缓慢的过程,因为那时需要更新很多数据)
- 我现在需要找出Lists需要更改的内容,并基本上拒绝对那些列表的api调用,其中包含特定元素不再可用的信息
需要检查的几件事,特别是对于MongoDB:
-
请确保没有循环引用(例如,如果类List上的属性$elements及其引用设置为true,请确保elements类上也没有引用List),并且映射是一致的。
-
在addElement函数中,如果引用保存在Element类上,请确保您也在函数内部调用$Element->setList($this)。(removeElement也是如此,必要时取消设置引用)
-
确保级联所有必要的操作。(例如级联:["持久"、"删除"、"刷新"或"全部"]
您可以使用检查您的映射
$ app/console doctrine:mongodb:mapping:info
最后,如果您希望该文档被删除,但您从代理对象中得到错误,则可以清除元数据缓存
$ app/console doctrine:mongodb:cache:clear-metadata
目前有效的Inperfect解决方案
我现在选择抛出一个新的Exception(重要的是不要让条令抛出一个,因为它会拒绝同一请求中的任何持久尝试)。
在PostLoad生命周期事件中,我现在检查以下内容(简化):
if ($document instanceof List) {
foreach ($document->getElements() as $element) {
// at this moment $element->getId() is already defined but not yet loaded from mongo
$result = $this->elementRepository->findBy(array(‘_id’ => $element->getId()));
if (sizeof($result)==0) {
throw new InvalidElementInList($element->getId());
}
}
}
在RestController中,这使我现在能够捕获这个特定的异常,并从列表中删除无效元素+向用户返回一个自定义视图,指示该元素已被删除。