On Sep 21, 2010, at 11:51 PM, Michael Hipp wrote: > On 9/21/2010 8:17 PM, Michael Bayer wrote: >> It definitely does not attempt an INSERT if id_ is set to a non-None value, >> assuming that row already exists in the DB, without something else in your >> model/usage causing that to happen. If id_ is None or the given id_ >> doesn't exist in the DB, you get an INSERT. auct_id has no direct effect >> here. > >> that also makes no sense since if you set "auct_id" manually, assuming >> old.auct_id is not None, it wouldn't be None in the UPDATE statement. > > These behaviors (opposite what we expect) are what I'm indeed seeing. > >> As usual, distilling down the behavior that appears wrong into a single file > > Attached. > > I'll be thrilled if you can figure out what really stupid thing I'm doing to > cause this. > > As always, many thanks for your help.
So here, the value of None for car.auction, merges into the session which becomes a pending change. The flush overwrites car.auct_id with None because car.auction has been set to None. The merge() process takes everything that is present on the incoming object and assigns it to the object that's in the session. So here when merge sets old.auction = None, this is the effect. So you want to merge an object where every attribute is either exactly the value that you want it to be, or it is not loaded or assigned to in any way (i.e. not present in __dict__). If you pop "auction" from __dict__ before the merge, or just don't assign to "auction" in the contructor of Car and also dont issue a "print car.auction" later on, the program succeeds. So for example, this works: new = Car() new.id_ = old.id_ new.lane = old.lane new = sess.merge(new) sess.commit() if you took the None assignments out of the constructor, all you need is "id_" and leave everything else untouched, and it succeeds. So the other thing, with the INSERT, you need to look at stack traces when these things happen: File "empty.py", line 72, in <module> new = sess.merge(new) File "sqlalchemy/orm/session.py", line 1165, in merge self._autoflush() File "sqlalchemy/orm/session.py", line 863, in _autoflush anytime you see _autoflush in a stack trace, that means that some state is in the session that you don't want it to be, and _autoflush is trying to push it out before its ready. That a "car" row is being INSERTed during autoflush, means that a Car object has been added to the session. The first thing you do is then ask "new in sess" to see if that's the case. Here, the issue is that you're mixing the usage of merge() with the usage of objects that are already in the session. "new" is added to the session via cascade: new = Car() new.id_ = old.id_ new.lane = old.lane new.auct_id = old.auct_id new.auction = old.auction assert new in sess # passes The ways to get around that effect are: - pass "cascade=None" to your 'cars' backref - this means, when you set somecar.auction = someauction, someauction is already in the session, 'somecar' doesn't get added automatically. cascade also affects what merge() does along relationships so when changing this make sure it has the cascades that you still want. - expunge "new" before you merge() it, but that's kind of messy. - don't set any relationships that are going to cascade it into the session I think the general rule is to compose the object for merge() carefully so that it only contains what state you want to be merged. "None" counts as state. I definitely want to add a note about what "the state of the given instance is copied" means, regarding things in __dict__. > > Michael > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To post to this group, send email to sqlalch...@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. > > <empty.py> -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@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.