2011-04-15 14 views
9

Tengo un nodo de clase con un mapeo autorreferencial 'children' (backref 'parent') que representa un árbol en SQLAlchemy y quiero seleccionar todo el árbol. Si lo hagoConstruir todo el árbol a partir de una relación de lista de adyacencia SQLAlchemy

session.query(Node).all() 

luego cada acceso a node.children activa una selección. Si hago una carga unido

session.query(Node).options(joinedload_all('children')).all() 

entonces el SQL emitido tiene una mesa innecesaria unirse ya que quiero todo el árbol (todos los nodos) de todos modos. ¿Hay alguna manera de hacer esto en SA o debería simplemente construir el árbol por mi cuenta fuera de SA?

Respuesta

12

No hay ningún problema con la propiedad principal, ya que toda la información necesaria ya está cargada en el objeto. SQLAlchemy solo tiene que buscar el objeto primario en la sesión y emitir una consulta solo cuando falta. Pero esto no funciona para los niños: la biblioteca no puede estar segura de que todos los objetos secundarios ya estén en la sesión. Así que usted puede construir el árbol mismo y dar instrucciones SQLAlchemy utilizar estos datos a través set_committed_value:

from collections import defaultdict 
from sqlalchemy.orm.attributes import set_committed_value 

nodes = session.query(Node).all() 

# Collect parent-child relations 
children = defaultdict(list) 
for node in nodes: 
    if node.parent: 
     children[node.parent.id].append(node) 

# Set collected values 
for node in nodes: 
    set_committed_value(node, 'children', children[node.id]) 
+1

impresionante. Mi duda al construir el árbol estaba ensuciando los objetos del nodo, set_committed_value es lo que necesito. Gracias. – SquaredLoss

Cuestiones relacionadas