[Sqlalchemy-tickets] Issue #4130: Chained contains_eager for inherited relationships (zzzeek/sqlalc
Brought to you by:
zzzeek
From: dima-starosud <iss...@bi...> - 2017-11-02 12:11:16
|
New issue 4130: Chained contains_eager for inherited relationships https://bitbucket.org/zzzeek/sqlalchemy/issues/4130/chained-contains_eager-for-inherited dima-starosud: This is using sqlalchemy 1.2.0b3. Please consider following code snippet. Sorry it's a bit long. It basically defines polymorphic models `_A`, `_B`, `_C`, `A1`, `B1`, `C1` and relationships between them `_A <-> _B`, `B1 <-> C1`. Then it `contains_eager` them in different ways `A1 * B1`, `B1 * C1`, `A1 * B1 * C1`, . Since it works for query`ab` and `bc`, I would expect it to also work for `abc`. Or give some warning/error. ``` #!python class Common: @declared_attr def id(cls): return Column(Integer, primary_key=True) @declared_attr def type(cls): return Column(String, nullable=False) @declared_attr def __mapper_args__(cls): return {'polymorphic_on': cls.type} Base = declarative_base() class _A(Base, Common): __tablename__ = 'a' b = relationship('_B', back_populates='a') class _B(Base, Common): __tablename__ = 'b' a_id = Column(Integer, ForeignKey(_A.id)) a = relationship(_A, back_populates='b') class _C(Base, Common): __tablename__ = 'c' b_id = Column(Integer, ForeignKey(_B.id)) class A1(_A): __mapper_args__ = {'polymorphic_identity': 'A1'} class B1(_B): __mapper_args__ = {'polymorphic_identity': 'B1'} class C1(_C): __mapper_args__ = {'polymorphic_identity': 'C1'} b1 = relationship(B1, backref='c1') configure_mappers() ab = Query(A1) \ .outerjoin(B1, A1.b).options(contains_eager(A1.b, alias=B1)) print(ab) # SELECT b.a_id AS b_a_id, b.type AS b_type, b.id AS b_id # , a.type AS a_type, a.id AS a_id # FROM ... bc = Query(B1) \ .outerjoin(C1, B1.c1).options(contains_eager(B1.c1, alias=C1)) print(bc) # SELECT b.a_id AS b_a_id, b.type AS b_type, b.id AS b_id # , c.b_id AS c_b_id, c.type AS c_type, c.id AS c_id # FROM ... abc = Query(A1) \ .outerjoin(B1, A1.b).options(contains_eager(A1.b, alias=B1)) \ .outerjoin(C1, B1.c1).options(contains_eager(A1.b, B1.c1, alias=C1)) print(abc) # doesn't contain "c": # SELECT b.a_id AS b_a_id, b.type AS b_type, b.id AS b_id # , a.type AS a_type, a.id AS a_id # FROM ... ``` There is workaround though. Looks like changing `A1.b` has an effect of how `B1.c1` is contained. ``` #!python B1.a = relationship(A1, back_populates='b') A1.b = relationship(B1, back_populates='a') configure_mappers() abc = Query(A1) \ .outerjoin(B1, A1.b).options(contains_eager(A1.b, alias=B1)) \ .outerjoin(C1, B1.c1).options(contains_eager(A1.b, B1.c1, alias=C1)) print(abc) # SELECT b.a_id AS b_a_id, b.type AS b_type, b.id AS b_id # , c.b_id AS c_b_id, c.type AS c_type, c.id AS c_id # , a.type AS a_type, a.id AS a_id # FROM ... ``` |