On Feb 8, 2008, at 2:01 PM, Richard Levasseur wrote: > Ok, so I'm talking about 2 slightly different things at once: One > is that sqlalchemy doesn't call the mapper extensions when loading > the data from the inherited tables. The second is that it can't > load instances unless a record in the inherited table exists. > > One: > By "2 record fetch" I meant, a single instance of Child requires one > record to be fetched from `parents` and another record to be fetched > from `kids`, and sqlalchemy is correctly doing this with the > inherited tables. What I'm pointing out is that, when it fetches > the record from the child table, it doesn't run the mapper > extensions (unless i'm doing it wrong). > 1) session.query(Parent).get(id) > 2) select ... from parents ... > 3) translate_row and translate row extensions > 4) populate instance and populate instance extensions > 5) I'm polymorphic and am a Child, so query kids: select ... from > kids ... > 6) populate instance (with the data from kids), but extensions > aren't run. (I don't see any calls to translate_row?) > 7) return instance
thats actually correct - the second query to the child table is not a top-level ORM query, its internal to the get() call, so we currently don't have any extension hooks there (all of that "call a second query" functionality was just introduced in 0.4.) However, the whole "_post_instance" step where that happens is optional. In your case, I really think you want to be using a polymorphic join or union so that the mapper can load parents and children from one query. You do this by specifying the "select_table" argument to the mapper(), and usually its an outerjoin among all the involved tables or in some cases can be a big UNION of all the separate subtables. But if your select_table only includes the base table, that will work too, it just wont populate the secondary attributes unless you did something else to make it happen (like in your extension). If you do that, the whole _post_instance() thing won't happen at all; your translate_row() will get the only row dealt with, as will your populate_instance(). So you *can* in theory issue a second SQL query within your own populate_instance() call that simulates what _post_instance() does, if you wanted to. Or I would think you could just load everything in one shot here using a series of outerjoins among all the tables; theres an example in the docs and in the examples/polymorphic folder illustrating how to load in that way. > > Two: > I've attached an example, essentially this: > > Table("parents", Column("id"), Column("type")) > Table("kids", Column("child_id"), Column("parent_id", > FK("parents.id"))) > engine.execute("insert into parents (id, type) values(1, 'child')") > # not inserting child record > session.query(Parent).get(1) # gives an error, "NoneType not > iteratable"; the row is None > > Note that no record exists in `kids`, this is intentional, it isn't > always guaranteed to be there because of the way the system behaves > (the workflow engine may change the type outside the application) > > It works in our current app (custom php) because when we save the > record, we check if the `child_id` is null, if it is we insert, > otherwise we update. During loading, if the `child_id` is null, we > just set everything else to null. yup, works if you do it like this: mapper(Parent, parents, polymorphic_on=parents.c.type, polymorphic_identity="parent", select_table=parents.outerjoin(kids), primary_key=[parents.c.id]) mapper(Child, kids, inherits=Parent, polymorphic_identity="child") note the "primary_key=[parents.c.id]" there, which is to override the fact that parents.outerjoin(kids) in fact has a primary key of [parents.c.id, kids.c.cid]. --~--~---------~--~----~------------~-------~--~----~ 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 [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---