On 29 Lis, 20:53, Michael Bayer <[email protected]> wrote: > On Nov 29, 2011, at 2:35 PM, Łukasz Czuja wrote: > > > Hello, > > > I'm trying to figure out a way to use Session.merge(o, load=False), on > > an object which is not bound to a session (Session.remove() used after > > the object was modified, but the changes were not commited). > > > When the object's state is modified (instance_state(o).modified == > > True) the session merge will fail with: > > > "merge() with load=False option does not support objects marked as > > 'dirty'. flush() all changes on mapped instances before merging with > > load=False." > > > So i need an rollback(o) on this object only. It might also be a good > > idea to add an argument to merge() to do just that. > > load=False is only a performance optimization. If you're passing it dirty > objects, the optimization cannot take place and guarantee consistent data. > It's not feasible for SQLAlchemy to "roll back" the attributes on an object, > as it quickly gets into edge cases regarding references and collections where > only the view from the relational database can really provide an accurate > picture; that's why objects are fully expired, so that attributes can be > refeshed from the database on access, instead of "rolled back".
That actually makes more sense. Haven't thought about references, good point. > > You'd have to figure a way to produce a clean object for merge() in the first > place if you'd like to avoid its state being reconciled with that of the > database. This is something that's outside the scope of what the ORM > provides. > > If it were me I'd not be using load=False for any use case other than plain > vanilla retrieval from a cache. If you want to optimize merge() for a > non-caching use case, pre-load the full set of objects that you expect to > pass to merge() using a series of SELECT statements, then ensure those > persistent objects remain referenced. When you merge in your dirty, detached > objects, the state on those objects will be reconciled with the object > already in the identity map, and no SQL will be emitted. I use a more naive approach now, I just assume that objects exist, and if commit throws an error, I shall reload the problematic rows. For now I will use: o = db_session.merge(o, load = instance_state(o).modified) I do not keep them forever, they expire or get reloaded, whichever comes first. Thanks for the insight -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
