In my application, I have a set of tables that model parts of what are conceptually composite objects, and I need to validate that the state of the objects is coherent before committing them to the database. In the course of building up the network of objects, the state may be temporarily inconsistent (because it will, in general, be impossible to maintain consistency at every step of the process), but I want to make sure it is consistent by the time it hits the database. I think the answer is to make a SessionExtension and use before_commit(), but I still have some questions about exactly how that works.
To make the question concrete, I have a one-to-many relationship, and the relevant state is the state of the parent+children composite. Any change to a child's attributes needs to trigger re-validation of the parent, and obviously any change in membership in the collection of children needs to trigger revalidation. In particular, if a child moves from one parent to another, then *both* parents must be re- validated before the transaction is committed. All this validation needs to occur even though the parent table is not modified in any of those cases. And I think I will likely want this to work also in a many-to-many relationship, where any change to the association table should trigger validation of all related (or newly unrelated) objects. Furthermore, I want to work with these objects as individual Parent and Child objects, not a single ParentWithChildren object. Or at a minimum, I want to be able to pass around and modify Child objects on their own; if I get the Children every time I ask for the Parent, that's fine. The @validates decorator is largely useless for this purpose, as it validates a particular attribute of a particular class, and it gets called at the wrong time, and in the case of collections, only gets called on append events, not remove events (afaict). So if I do this with a SessionExtension.before_commit(), I would have to iterate through the new, dirty, and deleted instances lists, inspect the type of each instance, and do whatever is required. I am not sure, though, how to handle the case of a change in membership in the parent/child relationship -- the child instance that is present in the dirty list will have only the new parent on it -- how do I find out what the old parent was, so I can validate it? If a flush has already occurred, the old value is already lost in the context of the current transaction, and I think that if I open a new transaction inside a before_commit() validator I'm just asking for trouble. Do I need to instrument the Child class with a descriptor that tracks changes to the parent and remembers the old parent? Or can I set the cascade option in such a way that the old parent will end up in the dirty list, even though there are no changes to its underlying table, and in fact it may never have been explicitly loaded into the session? (I must admit to be somewhat unsure of what the different cascade options do -- but they don't seem to be useful for tracking something like this.) And lastly, what do I do inside before_commit() if I want to prevent the commit from proceeding? Do I just raise an exception? Any particular type of exception, or is it my choice? Sorry for the long question, and thanks for any assistance, Randall --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---