SQLA can't be expected to do the "right thing" if you map to a table that is 
also stated as the "secondary" in a relationship elsewhere - that's not a 
condition it maintains track of.   It happens to handle the "team_contestants" 
relationship first, deletes from your mapped table which depending on backend 
either fails due to the remaining rows in team_contestant_table, or fails later 
because SQLA performs basic checks when mapped rows are deleted (that 
ConcurrentModificationError is there to catch specifically errors like this).   

This behavior, along with the hint to use "viewonly", is noted in the note at 
the bottom of 
http://www.sqlalchemy.org/docs/orm/relationships.html#association-object  , and 
also the docstring for "secondary" states at 
http://www.sqlalchemy.org/docs/orm/relationships.html?highlight=relationship#sqlalchemy.orm.relationship
 "The secondary keyword argument should generally only be used for a table that 
is not otherwise expressed in any class mapping."


On Dec 18, 2010, at 10:03 PM, Joseph Tate wrote:

> I have the schema described in the test script located here: 
> http://pastebin.com/qeB0vKVV
> 
> If you run the script, you can see that there is a 
> ConcurrentModificationError: when I go to delete the contest.  If I delete 
> the contestants first, there is no problem.  The problem seems to be caused 
> by the double link between "Contest" and "Contestant".  The first, an 
> indirect link via TeamContestant through polymorphic inheritance created by 
> the m1 mapper, and the second a backref created by the m2 mapper.  If I leave 
> the Contest.team_contestant relation off, the script executes successfully.  
> Removing that relation changes the order of the operations: when it works 
> successfully, all Slot updates happen before the first delete operation.  
> When it fails, the contestants are deleted before the slots are updated as 
> follows:
> 
> Echo output of a successful run:
> 2010-12-18 21:37:56,788 INFO sqlalchemy.engine.base.Engine.0x...2890 UPDATE 
> slot SET contest_id=? WHERE slot.id = ?
> 2010-12-18 21:37:56,788 INFO sqlalchemy.engine.base.Engine.0x...2890 (None, 1)
> 2010-12-18 21:37:56,788 INFO sqlalchemy.engine.base.Engine.0x...2890 UPDATE 
> slot SET contestant_id=? WHERE slot.id = ?
> 2010-12-18 21:37:56,788 INFO sqlalchemy.engine.base.Engine.0x...2890 (None, 2)
> 2010-12-18 21:37:56,789 INFO sqlalchemy.engine.base.Engine.0x...2890 UPDATE 
> slot SET contestant_id=? WHERE slot.id = ?
> 2010-12-18 21:37:56,789 INFO sqlalchemy.engine.base.Engine.0x...2890 (None, 3)
> 2010-12-18 21:37:56,789 INFO sqlalchemy.engine.base.Engine.0x...2890 DELETE 
> FROM team_contestant WHERE team_contestant.id = ?
> 2010-12-18 21:37:56,789 INFO sqlalchemy.engine.base.Engine.0x...2890 ((1,), 
> (2,))
> 2010-12-18 21:37:56,790 INFO sqlalchemy.engine.base.Engine.0x...2890 DELETE 
> FROM contestant WHERE contestant.id = ?
> 2010-12-18 21:37:56,790 INFO sqlalchemy.engine.base.Engine.0x...2890 ((1,), 
> (2,))
> 2010-12-18 21:37:56,790 INFO sqlalchemy.engine.base.Engine.0x...2890 DELETE 
> FROM contest WHERE contest.id = ?
> 2010-12-18 21:37:56,790 INFO sqlalchemy.engine.base.Engine.0x...2890 (1,)
> 
> Echo from an unsuccessful run:
> 2010-12-18 17:25:59,017 INFO sqlalchemy.engine.base.Engine.0x...2490 DELETE 
> FROM contestants WHERE contestants.contest_id = %(contest_id)s
> 2010-12-18 17:25:59,017 INFO sqlalchemy.engine.base.Engine.0x...2490 
> ({'contest_id': 267}, {'contest_id': 267})
> 2010-12-18 17:25:59,025 INFO sqlalchemy.engine.base.Engine.0x...2490 UPDATE 
> slots SET contest_id=%(contest_id)s WHERE slots.id = %(slot_id)s
> 2010-12-18 17:25:59,025 INFO sqlalchemy.engine.base.Engine.0x...2490 
> {'contest_id': None, 'slot_id': 4}
> 2010-12-18 17:25:59,026 INFO sqlalchemy.engine.base.Engine.0x...2490 UPDATE 
> slots SET contestant_id=%(contestant_id)s WHERE slots.id = %(slot_id)s
> 2010-12-18 17:25:59,027 INFO sqlalchemy.engine.base.Engine.0x...2490 
> {'contestant_id': None, 'slot_id': 8}
> 2010-12-18 17:25:59,027 INFO sqlalchemy.engine.base.Engine.0x...2490 UPDATE 
> slots SET contestant_id=%(contestant_id)s WHERE slots.slot_id = %(slot_id)s
> 2010-12-18 17:25:59,027 INFO sqlalchemy.engine.base.Engine.0x...2490 
> {'contestant_id': None, 'slot_id': 9}
> 
> I would expect the Contest.team_contestants relation, since it contains no 
> explicit cascade, to not take precedence over the more inclusive 
> Contest.contestants.  It looks like however that the rowcount calculation 
> takes one relation, while the delete takes the other.  Is there a bug there?
> 
> I can actually use viewonly on the team_contestants relation.  This seems to 
> cause the correct behavior to occur.  Luckily I'm not writing to the 
> team_contestant relation, so I don't think this will adversely affect my 
> application.
> 
> -- 
> 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.

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

Reply via email to