Hello all,

Short summary of my question: 

Is it possible to stop rollback() from expiring dirty objects?

Specifically, in the case where there are
 - local changes made outside to mapped objects outside of a transaction 
 - flush() is called
 - the flush fails

In this case SQLAlchemy will expire any objects that had local changes, and 
those changes are lost. I would ideally like get objects & session to be in 
the same state as they were before I called flush().

Longer explanation of my approach, in case I am just doing it wrong :)

I have a GUI application where users can load, view, and edit some database 
mapped objects. Stripped down, it's pretty simple stuff like this:

class Action(Base):
    __tablename__      = "action"
    id                 = Column(Integer, primary_key=True)
    description        = Column(Text)

class Step(Base, ActionSchemaMixin):
    __tablename__      = "step"
    id                 = Column(Integer, primary_key=True)
    id_action          = Column(Integer, ForeignKey(Action.id))

    action             = relationship(Action, backref='steps')

So the action has some attributes, and a number of steps, which have their 
own attributes. Users can select an action (or create a new one) - then 
add, remove, and update steps for that action from the GUI.

I have found it to be an extremely useful pattern to couple these widgets 
directly to the mapped objects they are dealing with, and let the various 
event handlers to update the mapped objects whenever the user alters the 
GUI.

The following pseudo-code should give you an idea

class ActionWidget(Widget):
    def __init__(action):
        self.action = action
        self.description_edit_widget = TextEditWidget(on_changed=self.
on_description_widget_changed)

     def on_description_widget_changed(self, new_description):
        self.action.description = new_description

I also have a widget for a list-of-steps that shows a summary for each, and 
allows you to add/remove new ones - and a widget for editing an individual 
step.

Because I have no control over how long the user will faff about when 
editing one of these actions, and we do not want long open transactions to 
the database, I have set up my session with the slightly controversial 
(autoflush=False, autocommit=True, expire_on_commit=False) options. I load 
up the action and all the steps, the user can take as long as they like 
mucking about with it - and when they press the 'Save' button, I just flush 
all the changes.

It works great, except if something goes wrong with the flushing. If some 
DB constraint is violated for example, the transaction created in flush() 
is rolled back. All my modified objects are expired, and any new ones are 
expunged, as faithfully described in the docs.

In this case though, it is unfortunate, because now I have a mismatch 
between what is in my GUI and the objects they are supposed to be 
displaying. I want to be able to warn my user about the problem and let 
them fix the one field that was wrong, without forcing them to loose all 
their changes and start again.

It is quite difficult for me to recreate the mapped objects changed state 
from the GUI elements alone, as there are temporary widgets created at 
times to edit certain attributes.

The only way around this that I can think of is to detach all the objects 
before coupling them to the GUI elements - then in my save function, 
somehow copying all of the updated/new objects before adding them to a 
session and attempting to commit the changes. I could get this to work, but 
think it might be fiddly when there are a mixture of new and dirty 
persisted objects.

Interestingly when creating a set of brand new objects, things are fine too 
- although they are expunged, they can be re-added to the session when the 
user is ready to try again.

hoping there is a simple answer but suspecting there isn't :)

All the best,

Philip

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to