从SQLAlchemy邻接列表关系构建整个树结构
我有一个叫做Node的类,它里面有一个自引用的映射'children'(反向引用'parent'),用来表示一个树结构,使用的是SQLAlchemy。我想要选择整个树。如果我这样做
session.query(Node).all()
那么每次访问node.children都会触发一次查询。如果我使用连接加载
session.query(Node).options(joinedload_all('children')).all()
那么生成的SQL会有一个不必要的表连接,因为我反正是想要整个树(所有节点)。有没有办法在SQLAlchemy中做到这一点,还是说我应该在SQLAlchemy之外自己构建这棵树呢?
1 个回答
13
父对象的属性没有问题,因为所有需要的信息已经加载到对象中了。SQLAlchemy只需要在会话中查找父对象,只有在缺失时才会发出查询。但对于子对象来说就不一样了:这个库不能确定所有的子对象是否已经在会话中。因此,你可以自己构建这个树形结构,并通过 set_committed_value
来告诉SQLAlchemy使用这些数据:
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])