Ленивая загрузка с Doctrine2 и Symfony2 с использованием DQL - PullRequest
37 голосов
/ 05 ноября 2011

У меня есть древовидная структура с родительским полем.В настоящее время я пытаюсь заставить все родительские узлы отображать путь к текущему узлу.

В основном я выполняю цикл 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.

Что не так с моим кодом?Я неправильно понял ленивую загрузку?

Большое спасибо, Hacksteak

Ответы [ 2 ]

7 голосов
/ 26 марта 2012

Похоже, вы используете модель смежности для хранения деревьев в реляционной базе данных. Это, в свою очередь, означает, что вам понадобится объединение для каждого уровня, чтобы получить всех предков одним запросом.

Поскольку вы уже используете библиотеку расширений Doctrine , я рекомендую взглянуть на компонент Tree .

2 голосов
/ 29 марта 2012

Мой ответ подразумевает не использование DQL, а создание NestedSetManager, который имеет доступ к вашему соединению DBAL, что позволяет использовать SQL. Я никогда не чувствовал, что ORM хорошо поработал с логикой запросов NestedSets.

С NestedSetManager вы можете написать множество чистых методов, и это действительно просто, потому что все эти запросы хорошо документированы. Смотрите эту ссылку . Некоторые из методов в моем NestedSetManager:

setNode();
setRoot();
loadNestedSet();
moveNodeUp();
modeNodeDown();
getRootNode();
addNodeSibling();
getNodesByDepth();
getParents();
getNodePath();
childExists();
addChildToNode();
renameNode();
deleteNode();
// And many more 

Вы можете иметь мяч и создавать множество функциональных возможностей NestedSet, если вы не связаны какой-то сложной функциональностью ORM.

Также - Symfony2 делает все это действительно очень простым. Вы создаете свой файл класса 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 привели меня в замешательство, и это решение работает очень хорошо. Если вас заставляют использовать DQL и у вас нет других вариантов, этот ответ, вероятно, будет неприемлемым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...