bojanb wrote: > > The root of the problem is inheritance. Let's say that I have a Person > class and an Employee class that inherits from it. I also have a > Meeting class that records meetings between two persons. > > A query on Meeting will always lazy load Employee's attributes, > regardless of any lazy/eagerload settings. E.g. if I want to print the > list of names of all persons somebody had meetings with and also their > position if they are employees (null if they're not), it will always > be done lazily. This is bad when I have, let's say, 100.000 Meetings. > > I guess I can build a custom join and work from that, but if I have > two levels of inheritance on one side and three levels on the other > side, I will have to write a six-way join, and this, I'm sure you'll > agree, sort of defeats the purpose of an object-relational mapper. > > Using classes mapped against multiple tables would elegantly solve > this problem, if I could only instantiate them (see my original post). > > Here's the code that shows attributes of inherited objects are loaded > lazily:
oh. you want with_polymorphic() for this. http://www.sqlalchemy.org/docs/05/mappers.html#controlling-which-tables-are-queried > > <code> > > from sqlalchemy import create_engine, Table, Column, Integer, String, > MetaData, ForeignKey > from sqlalchemy.orm import mapper, relation, sessionmaker, eagerload > from sqlalchemy.orm.mapper import validates > > DB_URI='postgres://postg...@localhost/postgres' #Replace this > accordingly > db_engine=create_engine(DB_URI, echo=False) > metadata = MetaData() > > class Person(object): > > def __init__(self, name): > self.name = name > > persons = Table('persons', > metadata, > Column('id', Integer, primary_key=True), > Column('type', String(1), nullable=False), > Column('name', String(100), nullable=False)) > > class Employee(Person): > > def __init__(self, name, position): > Person.__init__(self, name) > self.position = position > > employees = Table('employees', > metadata, > Column('id', Integer, ForeignKey('persons.id'), > primary_key=True), > Column('position', String(50), nullable=False)) > > class Meeting(object): > > def __init__(self, date, person_from, person_to): > self.date = date > self.person_from = person_from > self.person_to = person_to > > meetings = Table('meetings', > metadata, > Column('id', Integer, primary_key=True), > Column('date', String(8), nullable=False), > Column('person_from_id', Integer, ForeignKey > ('persons.id'), nullable=False), > Column('person_to_id', Integer, ForeignKey > ('persons.id'), nullable=False)) > > mapper(Person, persons, polymorphic_on=persons.c.type, > polymorphic_identity='P') > mapper(Employee, employees, inherits=Person, polymorphic_identity='E') > mapper(Meeting, meetings, properties={ > 'person_from': relation(Person, primaryjoin= > (meetings.c.person_from_id==persons.c.id)), > 'person_to': relation(Person, primaryjoin= > (meetings.c.person_to_id==persons.c.id)), > }) > > if __name__ == '__main__': > metadata.create_all(db_engine) > s=sessionmaker(bind=db_engine)() > try: > john = Person('John') > peter = Employee('Peter', 'clerk') > jack = Employee('Jack', 'manager') > m1 = Meeting('20090914', peter, john) > m2 = Meeting('20090915', peter, jack) > s.add_all([john, peter, jack, m1, m2]) > s.commit() > > db_engine.echo = True > #We now want to print the names and positions of everyone > Peter has ever met with > peters_meetings = s.query(Meeting).options(eagerload > ('person_to')).filter_by(person_from=peter).all() > for meeting in peters_meetings: > if meeting.person_to.type == 'P': > print meeting.date, meeting.person_to.name, None > else: > #Each print statement here will emit an SQL SELECT on > the employees table > print meeting.date, meeting.person_to.name, > meeting.person_to.position > > finally: > db_engine.echo = False > s.close() > metadata.drop_all(db_engine) > > </code> > > On Sep 11, 7:52 pm, "Michael Bayer" <mike...@zzzcomputing.com> wrote: >> have you tried using query + join() + contains_eager() ? any query you >> like can be used to build the object graph of your choice along >> relations(). >> >> >> >> bojanbwrote: >> >> > Here's something I've been struggling with recently. I'll include the >> > description of steps that got me here, as I believe the context will >> > make the question clearer. >> >> > It all started because I needed to show data (eg. in a list form) from >> > two related tables (classes). However, SQLAlchemy would emit one SQL >> > query for getting the objects of the first class, then one query each >> > for each access to attributes of the other class. It obviously loads >> > the attributes lazily, which is fine most of the time but grossly >> > inefficient in this case (as there can be thousands of records in the >> > first table). >> >> > "Aha, I'll use eagerload!" I thought. Alas, it doesn't seem to work >> > for inherited classes. A message in this group suggests that it >> > doesn't work for self-referential inherited classes, but in this case >> > it didn't work for plain inherited classes that don't contain >> > references to self. I'll write a test case that shows this later. >> >> > OK, I then decided to create a new class mapped against the two >> > tables, using join() in a mapper. This worked great regarding the >> > emitted SQL - session.query on new object generates the correct SQL >> > even with the (deep) inheritance tree that we have. Modifying the >> > attributes on of this object also writes them to correct respective >> > tables on commit. Great! The new class even conceptually fits nicely >> > with the rest of the application (e.g. I realized it's more of a >> > business object while the two underlying classes/tables are more of an >> > implementation detail; I'm not sure I even need the other two classes, >> > just the tables may be enough). Fantastic! >> >> > However, I can't figure how to create new instances of this (composite >> > as I call it) class. Since it contains fields both for autogenerated >> > primary key from the first class and foreign key from the second >> > class, I cannot set the foreign key because I don't know the primary >> > key before I commit, and commit fails because the foreign key is still >> > null. >> >> > Am I just missing something or am I attempting a no-no? I would think >> > that since I've defined the attributes to be identical in the >> > "oncluase", SQLAlchemy would now that the two are dependent and would >> > not complain about the null value. >> >> > Of course, I can always create the two other objects, but being able >> > to do it this way fits much more nicely with the rest of the >> > application. > > > --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---