原则2:如何处理丢失的关系文档


Doctrine2: How to handle missing relation documents

在一个巨大的数据集中,当删除一个文档时,我有时会出现不一致。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:

  1. 请确保没有循环引用(例如,如果类List上的属性$elements及其引用设置为true,请确保elements类上也没有引用List),并且映射是一致的。

  2. 在addElement函数中,如果引用保存在Element类上,请确保您也在函数内部调用$Element->setList($this)。(removeElement也是如此,必要时取消设置引用)

  3. 确保级联所有必要的操作。(例如级联:["持久"、"删除"、"刷新"或"全部"]

您可以使用检查您的映射

$ app/console doctrine:mongodb:mapping:info  
  1. 最后,如果您希望该文档被删除,但您从代理对象中得到错误,则可以清除元数据缓存

    $ 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中,这使我现在能够捕获这个特定的异常,并从列表中删除无效元素+向用户返回一个自定义视图,指示该元素已被删除。