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.

Reply via email to