On Oct 18, 2012, at 2:46 PM, Kent wrote:

> On Thursday, October 18, 2012 11:43:50 AM UTC-4, Michael Bayer wrote:
> 
> On Oct 17, 2012, at 9:55 PM, Kent wrote: 
> 
> > The attached script fails with "sqlalchemy.exc.InvalidRequestError: 
> > Instance '<Bug at 0x1e6f3d10>' has been deleted.  Use the make_transient() 
> > function to send this object back to the transient state." 
> > 
> > While this example is somewhat convoluted, I have a few questions about 
> > sqlalchemy behavior here: 
> > 
> > 1) At the session.flush(), even though the Rock and the bugs relationship 
> > have been expunged, the pending delete still is issued to the database.  
> > Would you expect/intend sqlalchemy to delete even after the expunge()? 
> 
> no, because the Rock you have merged has established that the Bug is no 
> longer associated with it.   You expunge the Rock, there's no Bug attached to 
> it to be expunged. 
> 
> 
> I am still slightly unclear on this: since sqlalchemy does delete the Bug, I 
> assume it is "marked for deletion" in some way when the 'bugs' relationship 
> is merged to the empty list [].  Is that accurate?  Please help me understand 
> why it does not show up in session.deleted, which is IdentitySet([])?

This particular "mark for deletion" occurs on line 1817 of session.py, within 
flush(), as it iterates through the current list of "dirty" objects and tests 
the object to see if it's an "orphan".  For Bug, this holds true and it's 
marked for deletion.

The "mark for deletion due to orphan" step always occurs within the flush 
process.   It is ultimately based on a test for the "parents" of the target 
object, which in the course of operation can be set and unset multiple times, 
so it is easier to track just this one flag and then convert to a "delete" 
within the flush, rather than to "delete"/"undelete" continuously, especially 
considering that the "delete" operation itself needs to continue cascading.

So to correct what I said about backrefs earlier, what is specifically 
happening here is, the backref is what enables "Bug" to be marked as "dirty" in 
the first place, that it's Bug.rock attribute has been modified.  flush() then 
sees its an orphan and marks it as such.   Without the backref, "bug" is in the 
Session, but is not marked as modified.   Rock is gone so nothing else happens, 
the Session is clean.

If "Rock" is not expunged, and the backref is not present on Bug, *then* the 
mark for deletion occurs in a different place, on line 473 of dependency.py 
where the "presort_saves" method of OneToManyDP (which is managing Rock.bugs) 
iterates through those records marked as "removed" from Rock.bugs, tests them 
for orphan, marks them as deleted.  So this is a later path for "mark for 
deletion", but is still based on the "orphan" flag status of the object.

-- 
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