Hello, * Apologies if this is a duplicate -- I attempted to post a few hours earlier but the result vanished. Could be that the earlier effort went off as a direct email to MB, instead of a post to this group as intended. "chris e" posted about this topic in April and I was trying to respond on that thread, but Google Groups won't take a response this long after.
Below, i've included a working test script that causes a ConcurrentModificationError. I'm wondering if that is the right result. I was working with this section of my code specifically to work out what cascade relationships I wanted to use in my tables and mappers, and while experimenting with various cascade options I fully expected to run into some exceptions where I couldn't delete some object because of its dependencies. But seeing a ConcurrentModificationError instead was a surprise. So I'm wondering if I've just got something set up wrong. I've done my best to trim this to a bare-bones minimal reproduction of the error, though it's still not tiny. Can't really cut out any more tables/classes/mappers without rendering the test script alien to what I'm actually working on. I'm modeling a rental reservation system. rentable Items are (multiple table) polymorphic. In this example the subclasses of Item have all been trimmed down to just one for clarity: Ski. Events are polymorphic, too; here I've included only most obvious subclass of event: Reservation. Each reservation has one customer associated with it. A reservation is associated to one or more Gearsets; each gearset has one or more Items. Items to Gearsets is actually many-to-many, and this is accomplished via three secondary tables: historyfile, currentfile, and futurefile. In this way an item has a distinct history of what sets (and thereby what rentals) it has been a part of in the past; a record of what it's doing right now, and what sets (and thereby rentals) it is reserved to be a part of in the future. If I had to guess, maybe this 3-way split of secondary/association tables is the thing that might be causing problems. I set it up that way to keep a strong, up-front distinction between events being in an item's future vs. its present case vs. its past. But I suppose I could actually achieve the same thing with all gearset<>item associations being in a single table, and just map the item's future/current/past to separate selects on that table. Right? But that's semi-off-topic. Again, I thought maybe I'd encounter some cascade problems but I didn't expect a ConcurrentModificationError to happen where it's happening here. Here's the test script and stack trace: # semi-minimal test example for ConcurrentModificationError: # Deleted rowcount 0 does not match number of objects deleted 1 import sqlalchemy from sqlalchemy import Table, BoundMetaData, Column from sqlalchemy import Integer, String, ForeignKey, PrimaryKeyConstraint from sqlalchemy import ForeignKeyConstraint, polymorphic_union from sqlalchemy import mapper, relation, backref from sqlalchemy import create_engine, create_session db = create_engine('postgres://postgres:[EMAIL PROTECTED]:5432/test2', encoding='utf-8') metadata = BoundMetaData(db) items = Table('items', metadata, Column('id', Integer, primary_key=True, autoincrement=True), Column('type', String(20))) skis = Table('skis', metadata, Column('id', Integer, primary_key=True), Column('data', Integer), ForeignKeyConstraint(['id'], ['items.id'])) events = Table('events', metadata, Column('id', Integer, primary_key=True), Column('etype', String(20)), Column('data', Integer)) reservations = Table('reservations', metadata, Column('id', Integer, ForeignKey('events.id'), primary_key=True), Column('customer_id', Integer, ForeignKey('customers.id')), Column('data', Integer)) gearsets = Table('gearsets', metadata, Column('id', Integer, primary_key=True), Column('event_id', Integer, ForeignKey('events.id')), Column('data', Integer)) historyfile = Table('historyfile', metadata, Column('item_id', Integer, ForeignKey('items.id'), primary_key=True), Column('gearset_id', Integer, ForeignKey('gearsets.id'), primary_key=True)) currentfile = Table('currentfile', metadata, Column('item_id', Integer, ForeignKey('items.id'), primary_key=True), Column('gearset_id', Integer, ForeignKey('gearsets.id'), primary_key=True)) futurefile = Table('futurefile', metadata, Column('item_id', Integer, ForeignKey('items.id'), primary_key=True), Column('gearset_id', Integer, ForeignKey('gearsets.id'), primary_key=True)) customers = Table('customers', metadata, Column('id', Integer, primary_key = True, autoincrement=True), Column('data', Integer)) class Item(object): pass class Ski(Item): pass class GearSet(object): pass class Event(object): pass class Reservation(Event): pass class Customer(object): pass item_join = polymorphic_union( { 'ski':items.join(skis), 'item':items.select(items.c.type=='item'), }, None, 'ijoin') item_mapper = mapper(Item, items, select_table=item_join, polymorphic_on=item_join.c.type, polymorphic_identity='item', properties = { 'history': relation(GearSet, secondary=historyfile, backref=backref('items_history', uselist=True), uselist=True), 'current': relation(GearSet, secondary=currentfile, backref=backref('items_current', uselist=True), uselist=False), 'future': relation(GearSet, secondary=futurefile, backref=backref('items_future', uselist=True), uselist=True)}) customer_mapper = mapper(Customer, customers) gearset_mapper = mapper(GearSet, gearsets, properties = { 'event': relation(Event, backref=backref('gearsets', uselist=True), uselist=False) }) event_join = polymorphic_union( { 'reservation':events.join(reservations), 'event':events.select(events.c.etype=='event'), }, None, 'ejoin') event_mapper = mapper(Event, events, select_table=event_join, polymorphic_on=event_join.c.etype, polymorphic_identity='event') reservation_mapper = mapper(Reservation, reservations, inherits=event_mapper, polymorphic_identity='reservation', properties = { 'customer': relation(Customer, backref=backref('reservations', uselist=True), uselist=False) }) ski_mapper = mapper(Ski, skis, inherits=item_mapper, polymorphic_identity='ski') if __name__ == '__main__': metadata.create_all() session = create_session() ski = Ski() gearset = GearSet() customer = Customer() reservation = Reservation() reservation.customer = customer gearset.items_future.append(ski) gearset.event = reservation session.save(reservation) session.flush() item = session.query(Item).selectfirst() item.future = [] session.delete(item) session.flush() session.close() metadata.drop_all() ConcurrentModificationError: Deleted rowcount 0 does not match number of objects deleted 1 Traceback (innermost last): File "h:\Documents and Settings\Eric\My Documents\rentalproject\deletetest.py", line 1, in <module> # semi-minimal test example for ConcurrentModificationError: File "h:\Documents and Settings\Eric\My Documents\rentalproject\deletetest.py", line 138, in <module> session.flush() File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\session.py", line 302, in flush self.uow.flush(self, objects) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 213, in flush flush_context.execute() File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 400, in execute UOWExecutor().execute(self, head) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1018, in execute self.execute_save_steps(trans, task) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1037, in execute_save_steps self.execute_childtasks(trans, task, False) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1055, in execute_childtasks self.execute(trans, child, isdelete) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1018, in execute self.execute_save_steps(trans, task) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1037, in execute_save_steps self.execute_childtasks(trans, task, False) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1055, in execute_childtasks self.execute(trans, child, isdelete) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1018, in execute self.execute_save_steps(trans, task) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1037, in execute_save_steps self.execute_childtasks(trans, task, False) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1055, in execute_childtasks self.execute(trans, child, isdelete) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1018, in execute self.execute_save_steps(trans, task) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1036, in execute_save_steps self.execute_dependencies(trans, task, True) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1051, in execute_dependencies self.execute_dependency(trans, dep, True) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 1029, in execute_dependency dep.execute(trans, isdelete) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\unitofwork.py", line 986, in execute self.processor.process_dependencies(self.targettask, [elem.obj for elem in self.targettask.polymorphic_todelete_elements if elem.obj is not None], trans, delete=True) File "h:\Python25\Lib\site-packages\sqlalchemy- 0.3.8-py2.5.egg\sqlalchemy\orm\dependency.py", line 372, in process_dependencies raise exceptions.ConcurrentModificationError("Deleted rowcount %d does not match number of objects deleted %d" % (result.rowcount, len(secondary_delete))) Any observations/suggestions appreciated. --~--~---------~--~----~------------~-------~--~----~ 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 [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---