2010-12-07 9 views
6

Tengo una configuración jerárquica de dos tablas donde la tabla A hace referencia a la tabla B, que luego hace referencia a un registro diferente en la tabla A, y así sucesivamente ... pero solo hasta una profundidad de recursión dada.¿Cómo se ajusta dinámicamente la profundidad de recursión para la carga ansiosa en el SQLAlchemy ORM?

Tengo esto funcionando bien usando SQLAlchemy y declarativo. También estoy usando con éxito la carga ansiosa con las propiedades lazy y join_depth en las relaciones de la tabla. Esto es según el SQLAlchemy documentation.

Sin embargo, esta disposición corrige la profundidad de recursión en 'join_depth' una vez en el tiempo de carga del programa ... pero con los datos que estoy utilizando sé la profundidad de recursión que debería usar cada vez. ¿Cómo puedo cambiar la profundidad de recursión utilizada por consulta?

He pensado en tocar el violín con la utilería join_depth en el objeto ORM base, pero esto no va a funcionar, ya que tengo una aplicación multi-hilo scoped_session donde eso sería peligroso (por no mencionar el hecho de que el parámetro es bastante difícil de localizar dentro de SQLAlchemy en tiempo de ejecución!).

También he examinado el uso de joinedload con la consulta, pero no veo cómo variar la profundidad con eso.

También soy consciente de la sintaxis 'WITH RECURSIVE' SQL disponible en algunas bases de datos a través de CTEs, pero tan grande como lo es, quiero evitar que por el momento ya que algunos DBs todavía no lo soportan (y tampoco hace SQLAlchemy - al menos no por el momento y no sin mucha personalización del dialecto).

Respuesta

3

No hay forma oficial de hacerlo, pero siguiendo el código produjo la siguiente solución para mí. Estoy usando el ejemplo de nodo del docs que vinculó.

class Node(Base): 
    __tablename__ = 'node' 
    id = Column(Integer, primary_key=True) 
    parent_id = Column(Integer, ForeignKey('node.id')) 
    data = Column(String(50)) 
    children = relationship("Node", 
        lazy="joined", 
        join_depth=2) 

Al momento de la creación, la propiedad children se le da un join_depth de 2. se registra este valor inicial en Node.children.property.join_depth. Sin embargo, cambiar este valor no hará nada. En init, la relación crea una "estrategia" para unirse, y esto copia el valor join_depth. Para cambiar la profundidad de combinación de la estrategia para la relación, establezca Node.children.property.strategy.join_depth.

>>> engine.echo = True # print generated queries 
>>> session.query(Node).all() # with default join_depth 
SELECT node.id AS node_id, node.parent_id AS node_parent_id, node.data AS node_data, node_1.id AS node_1_id, node_1.parent_id AS node_1_parent_id, node_1.data AS node_1_data, node_2.id AS node_2_id, node_2.parent_id AS node_2_parent_id, node_2.data AS node_2_data FROM node LEFT OUTER JOIN node AS node_2 ON node.id = node_2.parent_id LEFT OUTER JOIN node AS node_1 ON node_2.id = node_1.parent_id 
>>> Node.children.property.strategy.join_depth = 4 # new join depth 
>>> session.query(Node).all() # with new join depth 
SELECT node.id AS node_id, node.parent_id AS node_parent_id, node.data AS node_data, node_1.id AS node_1_id, node_1.parent_id AS node_1_parent_id, node_1.data AS node_1_data, node_2.id AS node_2_id, node_2.parent_id AS node_2_parent_id, node_2.data AS node_2_data, node_3.id AS node_3_id, node_3.parent_id AS node_3_parent_id, node_3.data AS node_3_data, node_4.id AS node_4_id, node_4.parent_id AS node_4_parent_id, node_4.data AS node_4_data FROM node LEFT OUTER JOIN node AS node_4 ON node.id = node_4.parent_id LEFT OUTER JOIN node AS node_3 ON node_4.id = node_3.parent_id LEFT OUTER JOIN node AS node_2 ON node_3.id = node_2.parent_id LEFT OUTER JOIN node AS node_1 ON node_2.id = node_1.parent_id 

Después de ajustar Node.children.property.strategy.join_depth, el número de combinaciones en la consulta generada cambia también.

Cuestiones relacionadas