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
-~----------~----~----~----~------~----~------~--~---

Reply via email to