On Nov 27, 2008, at 1:15 AM, David Harrison wrote:

>
> Hey all,
>
> I've got a situation where I have 2 object A and B, and a third object
> C that has a foreign key reference to both A and B.  I can have many
> C's that map to the same A.
>
> Now I've implemented a MapperExtension for C that has an after_delete
> function, and that function checks to see if the A that the deleted C
> was mapped to has any other mappings, and if there are no other
> mappings left, deletes the A.
>
> Now this works fine if I'm just deleting C's directly, however as soon
> as this happens during a cascade delete from some other object D that
> happens to have a mapping to C I get the below error - I'm assuming
> this is because sqlalchemy has a test condition that doesn't see my
> mapper coming, and freaks out when extra rows get nuked.
>
> "ConcurrentModificationError: Deleted rowcount 0 does not match number
> of objects deleted 4"


this error is because you've deleted some rows that the mapper is  
expecting to delete itself due to a "delete" cascade.   here is the  
full spectrum of approaches:

1. remove all "delete" cascades that reach "A" objects.  I'm guessing  
this is not an option.

2. move your function into a SessionExtension.after_flush() that  
issues your DELETEs after the unit of work has completed its tasks.  
When you work with SessionExtensions within after_flush(), peek into  
the "new", "dirty", and "deleted" lists, which haven't been reset at  
that point, to get the information you need.   This might be the  
easiest way to go.

3. it would probably work if you were to peek into the UOWContext  
itself to see if the A in question is already marked for deletion.    
This would also be pretty easy though I've never recommended this  
approach before so would have to be tested.  But unfortunately the  
UOWContext isn't passed to the mapper extension methods.    It is  
passed to the SessionExtension methods though, so you could grab it  
through one of those, something like:

import threading
from sqlalchemy.orm.attributes import instance_state

current_flush_context = threading.local()
class MySessionExt(SessionExtension):
     def before_flush(self, session, flush_context, instances):
         current_flush_context.context = flush_context

     def after_flush(self, session, flush_context, instances):
         del current_flush_context.context

class MyMapperExt(MapperExtension):
     def after_delete(self, mapper, connection, instance):
         ... get your A object to be deleted ...
         if not  
current_flush_context.context.is_deleted(instance_state(the_A_object)):
             ... delete the A ....



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

Reply via email to