37 votos

Carga lenta con Doctrine2 y Symfony2 utilizando DQL

Tengo una estructura de árbol con un padre de campo. Actualmente estoy tratando de conseguir todos los nodos primarios para mostrar la ruta de acceso al nodo actual.

Básicamente estoy haciendo un bucle while para procesar todos los nodos.

$current = $node->getParent();
while($current) {
  // do something
  $current = $current->getParent();
}

Utilizando el valor predeterminado findById método funciona. Debido a que la entidad tiene algunos campos agregados, estoy usando un repositorio personalizado método, para cargar todos los campos básicos con una consulta.

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();
}

Con ese código, la carga de los padres se produce un error. Yo sólo inmediata de los padres (dirigida por LEFT JOIN p.parent pp), pero no a los padres por encima. E. g. $node->getParent()->getParent() devuelve null.

Qué hay de malo con mi código? ¿He entendido mal la carga diferida cosa?

Muchas gracias, Hacksteak

7voto

tranver Puntos 393

Parece que usted está utilizando el modelo de adyacencia para el almacenamiento de los árboles en una base de datos relacional. Que a su vez significa, que usted necesitará una combinación para cada nivel para obtener todos los antepasados con una sola consulta.

Como ya se está utilizando la Doctrina de Extensión de la Biblioteca recomiendo para tener una mirada en el Árbol de componentes.

2voto

JustinP Puntos 547

Mi Respuesta no involucra el uso de DQL y en lugar de crear un NestedSetManager que tiene acceso a su DBAL de conexión así que usted puede utilizar SQL. Nunca me sentí como el ORM hizo un buen trabajo con NestedSets consulta de la lógica.

Con un NestedSetManager, a continuación, puede escribir un montón de métodos de limpieza y es muy simple debido a todas estas preguntas están bien documentados. Ver este enlace. Algunos de los método en mi NestedSetManager son:

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

Usted puede tener una pelota y crear una gran cantidad de crear NestedSet funcionalidad si no estás atado por un ORM es algo complejo de funcionalidad.

También, Symfony2 hace que todo esto realmente fácil. Crea tu NestedSetManager archivo de clase y de referencia en sus Servicios.yml y aprobar en su Dbal de conexión. La mina se parece a esto:

services:
    manager.nestedset:
        class: Acme\CoreBundle\Manager\NestedSetManager
        arguments: [ @database_connection ]

usted puede entonces tener acceso a su nestedsets con:

$path = $this->get('manager.nestedset')->setNode(4)->getNodePath(); // in your controller

Moraleja de la historia, ORM/NestedSets me volvía loco y esta solución funciona muy bien. Si usted está siendo forzado a utilizar DQL y no tienen otras opciones, esta respuesta probablemente no será aceptable.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X