从SQLAlchemy邻接列表关系构建整个树结构

9 投票
1 回答
2286 浏览
提问于 2025-04-16 15:49

我有一个叫做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])

撰写回答