On Sep 13, 2010, at 8:48 AM, Jon Siddle wrote: > I'm sure I'm missing something simple here, and any pointers in the right > direction would be greatly appreciated. > > Take for instance the following code: > > session = Session() > parents = session.query(Parent).options(joinedload(Parent.children)).all() > session.close() > > print parents[0].children # This works > print parents[0].children[0].parent # This gives a lazy loading error > > Adding the following loop before closing the session works (and doesn't hit > the DB): > > for p in parents: > for c in p.children: > c.parent > > As far as I can tell, the mapping is correct since: > > * It all works fine if I leave the session open > * If I don't use joinedload, and leave the session open it lazyloads correctly > > I'm surprised that: > > * It doesn't set both sides of the relation, considering it apparently knows > about them
This relationship is satisfied as you request it, and it works by looking in the current Session's identity map for the primary key stored by the many-to-one. The operation falls under the realm of "lazyloading" even though no SQL is emitted. If you consider that Child may have many related many-to-ones, all of which may already be in the Session, it would be quite wasteful for the ORM to assume that you're going to be working with the object in a detached state and that you need all of them. The Session's default assumption is that you're going to be leaving it around while you work with the objects contained, and in that way you interact with the database for as long as you deal with its objects, which represent "proxies" to the underlying transaction. When objects are detached, for reasons like caching and serialization to other places, normally you'd merge() them back when you want to use them again. So if it were me I'd normally be looking to not be closing the session. However, when working with detached objects is necessary, two approaches here you can use. One is a general approach that can load anything related, which is to load them in a @reconstructor. This is illustrated at http://www.sqlalchemy.org/trac/wiki/UsageRecipes/ImmediateLoading . It won't issue any extra SQL for the many-to-ones that are present in the session already. In the specific case you have above, you can also use a trick which is to use contains_eager(): parents = session.query(Parent).options(joinedload(Parent.children), contains_eager(Parent.children, Child.parent)).all() the above approach requires that Parent is one of the entities that you're requesting explicitly - i.e. if you were saying joinedload("foo", "bar", "bat"), it would be kind of impossible to target "bat.hohos" with contains_eager() due to the aliasing. this will do the get() of the Parent as you run through. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
