【发布时间】:2017-09-15 00:55:59
【问题描述】:
我有一个自引用的一对一关系(使用uselist=False),我试图在查询时急切地加载next_node。如果我删除 uselist=False 并将 next_node 作为检测列表访问,则该列表会正确加载到原始查询中。这是一个已知问题,还是我在尝试急切地加载 next_node 反向引用关系时做错了什么?
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import (
backref, joinedload, relationship, scoped_session, sessionmaker)
from sqlalchemy import create_engine, Column, Integer, ForeignKey, MetaData
class Node(declarative_base()):
__tablename__ = 'nodes'
id = Column(Integer, primary_key=True)
value = Column(Integer)
prev_node_id = Column(Integer, ForeignKey('nodes.id'), unique=True)
prev_node = relationship(
'Node',
uselist=False,
remote_side=[id],
backref=backref('next_node', uselist=False))
engine = create_engine('sqlite://', echo=True)
metadata = MetaData()
with engine.begin() as connection:
metadata = Node.metadata
metadata.create_all(connection)
session = scoped_session(sessionmaker(bind=engine))
a = Node()
session.add(a)
b = Node()
session.add(b)
b.prev_node = a
session.commit()
query = session.query(Node)
query = query.options(joinedload(Node.next_node))
print("executing joined query")
for n in query:
if n.next_node is not None:
print(n.id, n.next_node.id)
print("done!")
两个选择语句的结果:
...
executing joined query
2017-04-19 01:30:54,514 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2017-04-19 01:30:54,515 INFO sqlalchemy.engine.base.Engine SELECT nodes.id AS nodes_id, nodes.value AS nodes_value, nodes.prev_node_id AS nodes_prev_node_id, nodes_1.id AS nodes_1_id, nodes_1.value AS nodes_1_value, nodes_1.prev_node_id AS nodes_1_prev_node_id
FROM nodes LEFT OUTER JOIN nodes AS nodes_1 ON nodes.id = nodes_1.prev_node_id
2017-04-19 01:30:54,515 INFO sqlalchemy.engine.base.Engine ()
(1, 2)
2017-04-19 01:30:54,517 INFO sqlalchemy.engine.base.Engine SELECT nodes.id AS nodes_id, nodes.value AS nodes_value, nodes.prev_node_id AS nodes_prev_node_id
FROM nodes
WHERE ? = nodes.prev_node_id
2017-04-19 01:30:54,517 INFO sqlalchemy.engine.base.Engine (2,)
done!
但是,如果我确实不使用uselist=False 标志,我会得到预期的单个查询:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import (
backref, joinedload, relationship, scoped_session, sessionmaker)
from sqlalchemy import create_engine, Column, Integer, ForeignKey, MetaData
class Node(declarative_base()):
__tablename__ = 'nodes'
id = Column(Integer, primary_key=True)
value = Column(Integer)
prev_node_id = Column(Integer, ForeignKey('nodes.id'), unique=True)
prev_node = relationship(
'Node',
uselist=False,
remote_side=[id],
backref=backref('next_node'))
engine = create_engine('sqlite://', echo=True)
metadata = MetaData()
with engine.begin() as connection:
metadata = Node.metadata
metadata.create_all(connection)
session = scoped_session(sessionmaker(bind=engine))
a = Node()
session.add(a)
b = Node()
session.add(b)
b.prev_node = a
session.commit()
query = session.query(Node)
query = query.options(joinedload(Node.next_node))
print("executing joined query")
for n in query:
if n.next_node is not None and len(n.next_node) > 0:
print(n.id, n.next_node[0].id)
print("done!")
导致单个选择语句:
...
executing joined query
2017-04-19 01:29:30,570 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2017-04-19 01:29:30,571 INFO sqlalchemy.engine.base.Engine SELECT nodes.id AS nodes_id, nodes.value AS nodes_value, nodes.prev_node_id AS nodes_prev_node_id, nodes_1.id AS nodes_1_id, nodes_1.value AS nodes_1_value, nodes_1.prev_node_id AS nodes_1_prev_node_id
FROM nodes LEFT OUTER JOIN nodes AS nodes_1 ON nodes.id = nodes_1.prev_node_id
2017-04-19 01:29:30,571 INFO sqlalchemy.engine.base.Engine ()
(1, 2)
done!
【问题讨论】:
标签: python sqlalchemy