如果连接了backref,则子查询不会填充关系

时间:2013-12-11 13:05:04

标签: sqlalchemy

为什么CASE 4(参见输出)不提供相关的孩子。看起来如果它发生是因为如果backref是joinedload,则subqueryload不会填充关系。但这背后的逻辑是什么?这是一个错误吗?

请注意这些行之间的差异:

children1 = relationship('Child1', back_populates='parent', cascade='all', lazy='noload')
children2 = relationship('Child2', back_populates='parent', cascade='all', lazy='noload')
parent = relationship('Parent', back_populates='children1', cascade='all', lazy='joined')
parent = relationship('Parent', back_populates='children2', cascade='all', lazy='subquery')

parent = session3.query(Parent).options([joinedload('children1')]).get(1)
parent = session4.query(Parent).options([joinedload('children2')]).get(1)
parent = session5.query(Parent).options([subqueryload('children1')]).get(1)
parent = session6.query(Parent).options([subqueryload('children2')]).get(1)

-------- CODE ---------

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy import create_engine
from sqlalchemy.orm import relationship, sessionmaker, subqueryload, joinedload
from sqlalchemy.ext.declarative import declarative_base


Base = declarative_base()


class Parent(Base):
    __tablename__ = 'parent'

    id = Column(Integer, primary_key=True)
    name = Column(String(20))

    children1 = relationship('Child1', back_populates='parent', cascade='all', lazy='noload')
    children2 = relationship('Child2', back_populates='parent', cascade='all', lazy='noload')


class Child1(Base):
    __tablename__ = 'child1'

    id = Column(Integer, primary_key=True)
    name = Column(String(20))
    parent_id = Column(Integer, ForeignKey('parent.id', ondelete='CASCADE'))

    parent = relationship('Parent', back_populates='children1', cascade='all', lazy='joined')

    def __repr__(self):
        return repr((self.id, self.name, self.parent_id))


class Child2(Base):
    __tablename__ = 'child2'

    id = Column(Integer, primary_key=True)
    name = Column(String(20))
    parent_id = Column(Integer, ForeignKey('parent.id', ondelete='CASCADE'))

    parent = relationship('Parent', back_populates='children2', cascade='all', lazy='subquery')

    def __repr__(self):
        return repr((self.id, self.name, self.parent_id))


engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)

session1 = Session()
session1.add(Parent(id=1, name='parent'))
session1.add(Child1(id=1, name='child1_1', parent_id=1))
session1.add(Child1(id=2, name='child1_2', parent_id=1))
session1.add(Child2(id=1, name='child2_1', parent_id=1))
session1.add(Child2(id=2, name='child2_2', parent_id=1))
session1.commit()
session1.expunge_all()
session1.close()

session2 = Session()
parent = session2.query(Parent).get(1)
print 'CASE 1 (no options):', parent.id, parent.children1, parent.children2
session2.close()

session3 = Session()
parent = session3.query(Parent).options([joinedload('children1')]).get(1)
print 'CASE 2 (joined vs joinedload):', parent.id, parent.children1
session3.close()

session4 = Session()
parent = session4.query(Parent).options([joinedload('children2')]).get(1)
print 'CASE 3 (subquery vs joinedload):', parent.id, parent.children2
session4.close()

session5 = Session()
parent = session5.query(Parent).options([subqueryload('children1')]).get(1)
print 'CASE 4 (joined vs subqueryload):', parent.id, parent.children1
session5.close()

session6 = Session()
parent = session6.query(Parent).options([subqueryload('children2')]).get(1)
print 'CASE 5 (subquery vs subqueryload):', parent.id, parent.children2
session6.close()

输出

CASE 1 (no options): 1 [] []
CASE 2 (joined vs joinedload): 1 [(1, u'child1_1', 1), (2, u'child1_2', 1)]
CASE 3 (subquery vs joinedload): 1 [(1, u'child2_1', 1), (2, u'child2_2', 1)]
CASE 4 (joined vs subqueryload): 1 []
CASE 5 (subquery vs subqueryload): 1 [(1, u'child2_1', 1), (2, u'child2_2', 1)]

0 个答案:

没有答案
相关问题