On May 25, 2011, at 12:34 PM, mdob wrote:
> Consider a simple model like this:
>
> Library 1---* Shelf 1---* Book
>
> Accordingly our model has the following relationships declared:
>
> {tu wkelj kod z relationship wlaczajac backrefy)
>
> We will write a query with a join to get all three objects at once
>
> SELECT *
> FROM Library
> JOIN Shelf ON Library.id = Shelf.library_id
> JOIN Shelf ON Shelf.id = Book.shelf_id
> WHERE Library.name = 'TheLibrary' AND Shelf.loc = 'A1' AND Book.title
> = 'Ender''s Game'
>
> q = session.query(Library)
> q = q.join(Shelf)
> q = q.join(Book)
> q = q.filter(Library.name = "TheLibrary")
> q = q.filter(Shelf.loc = "A1")
> q = q.filter(Book.title = "Ender's Game")
> q = q.options(contains_eager('shelves', 'books'))
> result = q.all()
>
> Let's assume is only one record that meets the criteria (we have only
> one book with this title on shelf A1). We expect to get a single
> Library object with one-element collection of shelves, which has one
> element colection of books. This is indeed what seems to come back.
>
> However, upon access to a backref'd library _attribute_ in Shelf
> object another database query again Library gets automatically
> executed. This seems unneccesary because the related Library object is
> already loaded into the session.
>
> I've figured out that it has something to do with backref to from
> Shelf to Library so I added a line:
>
> q = q.options(contains_eager('shelves', 'Library'))
>
> and now the supurios query does not run.
>
> 1. Are these backref paths required? It can get messy with deeper
> relationships.
Backrefs usually take care of themselves as they are typically many-to-ones
that load directly from the identity map with no SQL query needed. If they are
not many to ones, and instead represent a collection, then it clearly has to go
to the DB to get the collection, even though one element of that collection was
loaded on the m2o side. So if you're doing one-to-one, you'd prefer to
contains_eager() the parent->FK side. I think that's what you're doing here.
In this case it appears you're saying Shelf.library is many-to-one but is still
invoking a load. This would happen in one of two cases: 1. the Library has
already been garbage collected from the Session by the time you call
Shelf.library, or 2. the many-to-one has a non-trivial join condition so that
the "get" logic cannot take place. The contains_eager() you're doing will
ensure Shelf.library is populated, as would "immediateload(Shelf.library)".
> 2. Indidentally accessing shelf attribute on Book DOES NOT result in a
> query? Why this inconsitence or am I missing something?
depends on #1 and #2 in my previous paragraph.
> 3. How will create_eager behave with many-to-many relationship?
m2m will work pretty much like the o2m case, you'd of course need to join to
your association table, which you can do via q.join(Library.shelf),
q.join(Shelf.book). I would not recommend using m2m for a scalar reference
however.
--
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.