如何在SQLAlchemy ORM中动态调整预加载的递归深度?
我有两个表的层级结构,表A引用表B,而表B又引用回表A中的不同记录,依此类推……不过,这种引用关系只能到达设定的递归深度。
我用SQLAlchemy和声明式方法把这个搞定了,效果很好。我还成功地使用了急加载,利用了表关系中的lazy
和join_depth
属性。这些都是根据SQLAlchemy的文档来做的。
不过,这种设置在程序加载时就固定了join_depth
的递归深度……但根据我使用的数据,我知道每次应该使用的递归深度。我该如何在每次查询时更改递归深度呢?
我考虑过调整基础ORM对象上的主join_depth
属性,但这行不通,因为我有一个多线程的作用域会话应用,这样做会很危险(更别提在运行时很难找到这个参数了!)。
我也想过用joinedload
来处理查询,但不明白如何在那样的情况下调整深度。
我还知道一些数据库支持的WITH RECURSIVE
SQL语法,通过CTE来实现,虽然这个方法很不错,但我暂时想避免使用,因为有些数据库仍然不支持(而且SQLAlchemy目前也不支持,至少没有大量的方言定制的话)。
1 个回答
虽然没有官方的做法,但我根据代码找到了一个解决方案。我使用的是你提供的文档中的Node示例。
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)
在创建时,children
这个属性被设置了一个叫join_depth
的值为2。这个初始值会记录在Node.children.property.join_depth
里。但是,改变这个值不会有什么效果。在初始化的时候,关系会创建一个“策略”来进行连接,并且这个策略会复制join_depth
的值。如果想要改变这个关系的连接深度,就需要设置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
在设置了Node.children.property.strategy.join_depth
之后,生成的查询中的连接数量也会发生变化。