使用DQL延迟加载Doctrine2和Symfony2
我有一个父域的树结构。 目前我正试图让所有的父节点显示当前节点的path。
基本上我正在做一个while循环来处理所有节点。
$current = $node->getParent(); while($current) { // do something $current = $current->getParent(); }
使用默认的findById
方法工作。 由于该实体具有一些聚合字段,因此我使用自定义存储库方法来加载具有一个查询的所有基本字段。
public function findNodeByIdWithMeta($id) { return $this->getEntityManager() ->createQuery(' SELECT p, a, c, cc, ca, pp FROM TestingNestedObjectBundle:NestedObject p JOIN p.actions a LEFT JOIN p.children c LEFT JOIN c.children cc LEFT JOIN c.actions ca LEFT JOIN p.parent pp WHERE p.id = :id ') ->setParameter('id', $id) ->setHint( \Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' ) ->getOneOrNullResult(); }
使用该代码,加载父母失败。 我只得到直接父母(由LEFT JOIN p.parent pp
),而不是上面的父母。 例如$node->getParent()->getParent()
返回null
。
我的代码有什么问题? 我误解了懒加载的东西吗?
谢谢你,哈克斯塔克
看起来你正在使用邻接模型在关系数据库中存储树。 这又意味着,你将需要每个级别的连接,以获得所有的祖先与一个单一的查询。
由于您已经在使用Doctrine扩展库,所以build议查看Tree组件。
我的答案涉及不使用DQL,而是创build一个NestedSetManager有权访问您的DBAL连接,所以你可以使用SQL。 我从来没有觉得ORM的NestedSets查询逻辑做得很好。
使用NestedSetManager
,您可以编写一堆干净的方法,这非常简单,因为所有这些查询都有详细的logging。 看到这个链接 。 我的NestedSetManager中的一些方法是:
setNode(); setRoot(); loadNestedSet(); moveNodeUp(); modeNodeDown(); getRootNode(); addNodeSibling(); getNodesByDepth(); getParents(); getNodePath(); childExists(); addChildToNode(); renameNode(); deleteNode(); // And many more
如果你没有被ORM的复杂function束缚,你可以创build一个球并创build大量的NestedSetfunction。
另外 – Symfony2使这一切真的很容易。 您可以创build您的NestedSetManager类文件,并在您的Services.yml中引用它,并传入您的Dbal连接。 我看起来像这样:
services: manager.nestedset: class: Acme\CoreBundle\Manager\NestedSetManager arguments: [ @database_connection ]
您可以使用以下方式访问您的嵌套集:
$path = $this->get('manager.nestedset')->setNode(4)->getNodePath(); // in your controller
道德的故事,ORM / NestedSets驱使我疯狂,这个解决scheme工作得很好。 如果你被迫使用DQL,没有其他select,这个答案可能不会被接受。