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

9

我有一个类Node,其中包含一个自引用映射'children'(反向参考'parent'),用于表示SQLAlchemy中的一棵树,我想选择整个树。如果我这样做:

session.query(Node).all()

那么每次访问node.children都会触发一个选择操作。如果我进行连接加载

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

如果我需要整个树,那么所发出的SQL具有无必要的表联接。在SA中是否有方法可以实现这一点,或者我应该在SA之外自己构建树?

1个回答

13

parent属性没有问题,因为对象中已经加载了所有需要的信息。SQLAlchemy只需在会话中查找父对象,并且仅在缺失该对象时发出查询。但是对于子对象,情况并非如此:该库无法确定所有子对象是否已经在会话中。因此,您可以自己构建树,并指示SQLAlchemy使用此数据通过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
太棒了。我对自己构建树的犹豫在于会污染节点对象,set_committed_value正是我所需要的。谢谢。 - SquaredLoss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接