Thanks for the quick response! I implemented your suggestion and I think that's perfectly fine for me, as there's no use case for loading ConfigParam instances on their own.
cheers Am Mittwoch, 8. April 2015 17:16:44 UTC+2 schrieb Michael Bayer: > > > > On 4/8/15 3:22 AM, Sebastian Eckweiler wrote: > > Hi there - > > I'm having trouble working with backrefs of detached objects. > I'm basically working with a extended version of the code below: > > class Config(Base): > __tablename__ = 'config' > > ID = Column('ID', Integer, primary_key=True) > name = Column('name', String) > last_modified = Column('last_modified', DateTime, default=now, > onupdate=now) > > params = relationship('ConfigParam', backref='config', lazy=False) > > class ConfigParam(Base): > > __tablename__ = 'config_params' > > ID = Column('ID', Integer, primary_key=True) > ConfigID = Column('ConfigID', Integer, ForeignKey('config.ID'), > nullable=False) > > key = Column('key', String) > value = Column('value', Float) > > Now when I load a Config instance I'd have assumed that > Config.params[0].config should be populated - since the eager query > contains all necessary information. > > A load that can be resolved to using the session's identity map instead of > SELECT is still a load nonetheless. You would need a lazy setting on the > backref as well. Since these are many-to-ones and the lazyload pulls from > identity map, I suggest "immediate". > > Using these settings at the mapping level does mean however that if you > load a ConfigParam object by itself, it will, for a clean session, > immediately issue a second SELECT statement for its Config object. > > > > > Testing this with a sqlite engine using the following code: > > > s = Session() > c = Config(name='my_config') > c.params += [ConfigParam(key='a', value=1), > ConfigParam(key='b', value=2)] > s.add(c) > s.commit() > s.close() > del c > > # reload from new session: > logging.info('\n\n') > logging.info('Starting with new session:') > s = Session() > c = s.query(Config).filter(Config.name=='my_config').one() > s.close() > for p in c.params: > logging.info('Params:%s = %s' % (p.key, p.value)) > for p in c.params: > logging.info('backref: config = %s' % p.config) > > however produces (omitting the create_all) the following output: > > INFO:sqlalchemy.engine.base.Engine:() > INFO:sqlalchemy.engine.base.Engine:COMMIT > INFO:sqlalchemy.engine.base.Engine:BEGIN (implicit) > INFO:sqlalchemy.engine.base.Engine:INSERT INTO config (name, > last_modified) VALUES (?, ?) > INFO:sqlalchemy.engine.base.Engine:('my_config', '2015-04-08 > 09:04:16.111000') > INFO:sqlalchemy.engine.base.Engine:INSERT INTO config_params ("ConfigID", > "key", value) VALUES (?, ?, ?) > INFO:sqlalchemy.engine.base.Engine:(1, 'a', 1.0) > INFO:sqlalchemy.engine.base.Engine:INSERT INTO config_params ("ConfigID", > "key", value) VALUES (?, ?, ?) > INFO:sqlalchemy.engine.base.Engine:(1, 'b', 2.0) > INFO:sqlalchemy.engine.base.Engine:COMMIT > INFO:root: > > > INFO:root:Starting with new session: > INFO:sqlalchemy.engine.base.Engine:BEGIN (implicit) > INFO:sqlalchemy.engine.base.Engine:SELECT config."ID" AS "config_ID", > config.name AS config_name, config.last_modified AS config_last_modified, > config_params_1."ID" AS "config_params_1_ID", config_params_1."ConfigID" AS > "config_params_1_ConfigID", config_params_1."key" AS config_params_1_key, > config_params_1.value AS config_params_1_value > FROM config LEFT OUTER JOIN config_params AS config_params_1 ON > config."ID" = config_params_1."ConfigID" > WHERE config.name = ? > INFO:sqlalchemy.engine.base.Engine:('my_config',) > INFO:sqlalchemy.engine.base.Engine:ROLLBACK > INFO:root:Params:a = 1.0 > INFO:root:Params:b = 2.0 > Traceback (most recent call last): > File "D:/Assess/Kiln/assess/scratch/sqla_example.py", line 77, in > <module> > logging.info('backref: config = %s' % p.config) > File > "D:\Anaconda\envs\assess\lib\site-packages\sqlalchemy\orm\attributes.py", > line 239, in __get__ > return self.impl.get(instance_state(instance), dict_) > File > "D:\Anaconda\envs\assess\lib\site-packages\sqlalchemy\orm\attributes.py", > line 591, in get > value = self.callable_(state, passive) > File > "D:\Anaconda\envs\assess\lib\site-packages\sqlalchemy\orm\strategies.py", > line 507, in _load_for_state > (orm_util.state_str(state), self.key) > sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <ConfigParam at > 0x307d898> is not bound to a Session; lazy load operation of attribute > 'config' cannot proceed > > I'm somewhat new to ORM's - > naively I had assumed the backref should/could be loaded at the same time > the parent is eagerly loaded, since all required information is retrieved > in the above query. > Is there anything I'm missing here? > > ps: This is on sqlalchemy 0.9.8 - if that should matter. > > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+...@googlegroups.com <javascript:>. > To post to this group, send email to sqlal...@googlegroups.com > <javascript:>. > Visit this group at http://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. > > > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.