[sqlalchemy] Re: Sharing join between main query and eagerload

2009-08-14 Thread Michael Bayer


On Aug 14, 2009, at 8:06 PM, David Bolen wrote:


 This feels like something that I ought to be able to find already
 answered somewhere but I've been searching the archives and the
 documentation and haven't been able to discover it.

 Is it possible to construct an ORM query that includes eagerloaded
 related objects such that the outer joins due to eagerload options and
 regular joins to the same tables in the main query can be
 consolidated?

two sources of info on this use case:

http://www.sqlalchemy.org/trac/wiki/FAQ#ImusinglazyFalsetocreateaJOINOUTERJOINandSQLAlchemyisnotconstructingthequerywhenItrytoaddaWHEREORDERBYLIMITetc.whichreliesupontheOUTERJOIN

http://www.sqlalchemy.org/docs/05/mappers.html?highlight=contains_eager#routing-explicit-joins-statements-into-eagerly-loaded-collections


good luck !







 For example if Session and Period are mapped object classes (to tables
 sessions and periods), with a mapper relation session defined
 between Period and Session, then a query like:

   query(Period).options(eagerload('session'))

 will select from periods with an aliased outer join to sessions in  
 order
 to eager load the related sessions row.

 However, if I need to filter the query based on the related session to
 limit the periods returned, and try something like:

   query(Period).join(Session).filter(Session.field == value).\
   options(eagerload('session'))

 then, regardless of using join(Session) or outerjoin(Session), I get
 two distinct joins between Period and Session, and does seem to resort
 in more database work based on explain output (from PostgreSQL).

 Since I know that I'm going to be doing the join to eager load the
 related object, it would be nice if the fields from that join could be
 used in the filtering operation.  But I haven't been able to figure
 out how to get SA to make use of them.

 Is there a way to either construct the initial ORM query so that the
 joins can be re-used for eagerloading the associated objects, or
 conversely so that the implicit joins created by the eagerload options
 can be used to filter the primary query?

 I'm currently using SA 0.5.4p2

 Thanks.

 -- David


 


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Sharing join between main query and eagerload

2009-08-14 Thread David Bolen

Michael Bayer mike...@zzzcomputing.com writes:

 http://www.sqlalchemy.org/docs/05/mappers.html?highlight=contains_eager#routing-explicit-joins-statements-into-eagerly-loaded-collections

Ok, that's embarrassing... I even recall skimming that section, but
now looking at it can't for the life of me figure out why I skipped
past it.  Even if I didn't fully grok it the first paragraph obviously
shows it is intended for my use case.  Sigh.

If I may ask for one clarification though - contains_eager is like
eagerload and doesn't support working like eagerload_all, right?  In
other words, I need to add contain_eager options for each step through
a multi-stage join, correct?

I think that matches the behavior I'm seeing, but the example in the
documentation that showed Users-orders-Order-items-Item seemed to
imply it wouldn't be necessary.

For example, with these mappings/relationships:

class ClassPeriod(object): pass
class Class_(object): pass
class Session(object): pass
class Weekday(object): pass

mapper(ClassPeriod, 'class_periods', autoload=True,
   properties = { 'class_': relation(Class_, backref='periods'),
  'weekday_': relation(Weekday, lazy=False) })
mapper(Class_, 'classes', autoload=True,
   properties = { 'session': relation(Session, backref='classes'),
  'type': relation(ClassType, backref='classes') })
mapper(Session, 'sessions' autoload=True)
mapper(Weekday, 'weekday', autoload=True)

then a query like:

query(ClassPeriod).join(Class_, Session).\
   options(contains_eager('class_','session'))

doesn't seem to perform the eager loading:

SELECT class_periods.class_id AS class_periods_class_id,
class_periods.weekday AS class_periods_weekday,
class_periods.start_time AS class_periods_start_time,
class_periods.duration AS class_periods_duration, weekdays_1.weekday
AS weekdays_1_weekday, weekdays_1.day AS weekdays_1_day
FROM class_periods JOIN classes ON classes.class_id =
class_periods.class_id JOIN sessions ON sessions.session_id =
classes.session_id LEFT OUTER JOIN weekdays AS weekdays_1 ON
weekdays_1.weekday = class_periods.weekday

but if I add the intermediate class_ relationship:

query(ClassPeriod).join(Class_, Session).\
   options(contains_eager('class_'),
   contains_eager('class_','session'))

then it adds both the classes.* and sessions.* columns for eager loading:

SELECT sessions.session_id AS sessions_session_id, sessions.site_id AS
sessions_site_id, sessions.name AS sessions_name, sessions.start_date
AS sessions_start_date, sessions.end_date AS sessions_end_date,
classes.class_id AS classes_class_id, classes.session_id AS
classes_session_id, classes.class_type_id AS classes_class_type_id,
classes.start_date AS classes_start_date, classes.end_date AS
classes_end_date, classes.capacity AS classes_capacity,
classes.overfill AS classes_overfill, class_periods.class_id AS
class_periods_class_id, class_periods.weekday AS
class_periods_weekday, class_periods.start_time AS
class_periods_start_time, class_periods.duration AS
class_periods_duration, weekdays_1.weekday AS weekdays_1_weekday,
weekdays_1.day AS weekdays_1_day
FROM class_periods JOIN classes ON classes.class_id =
class_periods.class_id JOIN sessions ON sessions.session_id =
classes.session_id LEFT OUTER JOIN weekdays AS weekdays_1 ON
weekdays_1.weekday = class_periods.weekday

Given the above, I'm not sure how the Users/Order/Item example, which
only had the single contains_eager('orders','items') would works?

Thanks.

-- David


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@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
-~--~~~~--~~--~--~---