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.

Reply via email to