On Aug 1, 2011, at 6:25 AM, Torsten Landschoff wrote: > Hello world, > > I am tearing my hair about my SQLAlchemy usage in a GUI application, > especially to get it error tolerant. > > Usually the GUI filters user inputs before they are thrown at SQLAlchemy > to store it into the database. If that fails, however, it can happen > that data is thrown at the database that leads to a rollback because of > e.g. violated foreign key constraints. > > If that happens, the session rolls back (fine) but the GUI still shows > the state that I tried to write into the database. Being MVC, I would > need all database object to fire a "changed" event so they are pulled > fresh from the database.
The Session's default behavior is to expire fully the state present after a rollback occurs. The next access of any attribute will guaranteed pull fresh from the DB in a new transaction. I'm assuming you know this, and that there is something additional here you're looking for, like an event to the GUI to actually re-access the attributes, or something. > > I tried using the after_commit extension (SQLAlchemy 0.6.8) to do this. > Paraphrased, this works like this: > > def after_rollback(self, session): > for instance in session: > instance.signal_changed() > > This works fine if the transaction being rolled back is the toplevel > transaction. However, if that is a nested transaction, this destroys my > session state (as the listeners try to load from the database): > > InvalidRequestError: This Session's transaction has been rolled back by > a nested rollback() call. To begin a new transaction, issue > Session.rollback() first. A surprise for me. Yes the after_rollback() seems to only fire after an actual database rollback. This is a bug in that there is no way to catch soft rollbacks. I can't change the event, as it is integral in transactional extensions like that supplied for Zope; a new one will have to be added and the docs for after_rollback() will need to be updated. Ticket #2241 is added for this and is completed. You can now use the 0.7 tip and use the after_soft_rollback() event in conjunction with the is_active flag: @event.listens_for(Session, "after_soft_rollback") def do_something(session, previous_transaction): if session.is_active: session.execute("select * from some_table") http://www.sqlalchemy.org/trac/ticket/2241 http://hg.sqlalchemy.org/sqlalchemy/rev/94d54a7e4d49 -- 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.