[Sqlalchemy-tickets] Issue #4156: Error when selectin eager loading on polymorphic subtypes (zzzeek
Brought to you by:
zzzeek
From: Theron L. <iss...@bi...> - 2018-01-07 22:14:04
|
New issue 4156: Error when selectin eager loading on polymorphic subtypes https://bitbucket.org/zzzeek/sqlalchemy/issues/4156/error-when-selectin-eager-loading-on Theron Luhn: I'm attempting to use selectin eager loading on polymorphic subtypes using the strategy laid out here: http://docs.sqlalchemy.org/en/latest/orm/inheritance_loading.html#eager-loading-of-specific-or-polymorphic-subtypes Here's some example code: ``` #!python from sqlalchemy import String, Integer, Column, create_engine, ForeignKey, inspect from sqlalchemy.orm import relationship, Session, subqueryload, selectinload from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Company(Base): __tablename__ = 'company' id = Column(Integer, primary_key=True) name = Column(String, nullable=False) employees = relationship('Employee') class Employee(Base): __tablename__ = 'employee' id = Column(Integer, primary_key=True) type = Column(String, nullable=False) name = Column(String, nullable=False) company_id = Column(Integer, ForeignKey('company.id'), nullable=False) __mapper_args__ = { 'polymorphic_on': 'type', 'with_polymorphic': '*', } class Programmer(Employee): __tablename__ = 'programmer' id = Column(Integer, ForeignKey('employee.id'), primary_key=True) languages = relationship('Language') __mapper_args__ = { 'polymorphic_identity': 'programmer', } class Manager(Employee): __tablename__ = 'manager' id = Column(Integer, ForeignKey('employee.id'), primary_key=True) something = Column(String) __mapper_args__ = { 'polymorphic_identity': 'manager', } class Language(Base): __tablename__ = 'language' id = Column(Integer, primary_key=True) programmer_id = Column( Integer, ForeignKey('programmer.id'), nullable=False, ) name = Column(String, nullable=False) engine = create_engine('postgresql://localhost:5432/sa', ) Base.metadata.drop_all(engine) Base.metadata.create_all(engine) db = Session(engine, enable_baked_queries=False) company = Company( id=1, name='Foobar Corp', employees=[Programmer( id=1, name='John Smith', languages=[Language(id=1, name='Python')], ), Manager( id=2, name='Foo', something='foo', )], ) db.add(company) db.flush() db.expunge_all() company = db.query(Company).filter( Company.id == 1, ).options( selectinload(Company.employees.of_type(Programmer)).selectinload(Programmer.languages), ).one() print(company.employees) ``` This results in: ``` Traceback (most recent call last): File "scratchpad/sqlalchemy_polymorphic_loading_bug.py", line 86, in <module> selectinload(Company.employees.of_type(Programmer)).selectinload(Programmer.languages), File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 2837, in one ret = self.one_or_none() File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 2807, in one_or_none ret = list(self) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 97, in instances util.raise_from_cause(err) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause reraise(type(exception), exception, tb=exc_tb, cause=cause) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 187, in reraise raise value File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 85, in instances post_load.invoke(context, path) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 750, in invoke self.load_keys, *arg, **kw) File "<string>", line 1, in <lambda> File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py", line 1966, in _load_for_path lambda x: x[0] File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py", line 1958, in <dictcomp> data = { File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 97, in instances util.raise_from_cause(err) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause reraise(type(exception), exception, tb=exc_tb, cause=cause) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 187, in reraise raise value File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 85, in instances post_load.invoke(context, path) File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 750, in invoke self.load_keys, *arg, **kw) File "<string>", line 1, in <lambda> File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py", line 1987, in _load_for_path state.get_impl(self.key).set_committed_value( File "/Users/luhn/Code/revenue/.env/lib/python3.6/site-packages/sqlalchemy/orm/state.py", line 423, in get_impl return self.manager[key].impl KeyError: 'languages' ``` This only happens when a Manager object is in the employees relationship. If employees only contains programmers, it works fine. This only happens when using selectinload, using subqueryload works fine. I'm running the current master branch (1.2.0 doesn't work due to #4153) |