On 13/09/10 16:45, Michael Bayer wrote:
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.
I'm not sure I see what you're saying here. I've explicitly asked for
"all children relating to parent" and these are correctly queried and
loaded. While they are being added to the parent.children list, why not
also set each child.parent since this is known? I don't see how this is
wasteful, but I may be missing something. I'm not suggesting it should
touch relations that I haven't explicitly told it to eagerly load. The
likes of Hibernate (yes, it's a very different beast) load both sides of
the relation at once.
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.
I'm closing the session before I forward the objects to the view
template in a web application. The template has no business doing
database operations, and the controller *should* make sure all DB work
has been done. In my case, I know I'll never need to write back
to the DB.
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()
This seems to address my problem directly. It's still a bit redundant,
but from my initial tests it seems to solve my problem.
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.
I'm only interested in making sure both sides of the same relation are
loaded; so this isn't a problem at all.
so let me also back that up, that we've always planned on adding an "immediateload"
option that would just fire off any lazyloader as the query fetches results. A really short
patch that adds "immediateload()" is athttp://www.sqlalchemy.org/trac/ticket/1914 and
hopefully will be in 0.6.5 pending further testing.
We'll have to support 0.5 for some time, but it's good to know a
shortcut is coming.
Thanks a lot for your help.
Jon
--
Jon Siddle, CoreFiling Limited
Software Tools Developer
http://www.corefiling.com
Phone: +44-1865-203192
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en.