]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- fixed bug where delete-orphan basically didn't work with many-to-many relationships...
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 19 Jan 2007 03:18:46 +0000 (03:18 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 19 Jan 2007 03:18:46 +0000 (03:18 +0000)
backref presence generally hid the symptom

CHANGES
lib/sqlalchemy/orm/dependency.py
test/orm/cascade.py

diff --git a/CHANGES b/CHANGES
index c85fef9676b5df11fd578523df690ba274e59644..fe16a2acc54af8f4af799654b6c1db3cc74af9fa 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -52,6 +52,8 @@
   - some deeper error checking when compiling relations, to detect an ambiguous "primaryjoin"
   in the case that both sides of the relationship have foreign key references in the primary
   join condition
+  - fixed bug where delete-orphan basically didn't work with many-to-many relationships [ticket:427],
+  backref presence generally hid the symptom
   - added a mutex to the mapper compilation step.  ive been reluctant to add any kind
   of threading anything to SA but this is one spot that its its really needed since mappers
   are typically "global", and while their state does not change during normal operation, the 
index e4e351d268b9b698dae8f47f37d4a80be20ace55..9887025a6c12c15eba7384212b0d2124191b3af4 100644 (file)
@@ -320,7 +320,16 @@ class ManyToManyDP(DependencyProcessor):
             connection.execute(statement, secondary_insert)
 
     def preprocess_dependencies(self, task, deplist, uowcommit, delete = False):
-        pass
+        #print self.mapper.mapped_table.name + " " + self.key + " " + repr(len(deplist)) + " preprocess_dep isdelete " + repr(delete) + " direction " + repr(self.direction)
+        if not delete:
+            for obj in deplist:
+                childlist = self.get_object_dependencies(obj, uowcommit, passive=True)
+                if childlist is not None:
+                    for child in childlist.deleted_items():
+                        if self.cascade.delete_orphan and childlist.hasparent(child) is False:
+                            uowcommit.register_object(child, isdelete=True)
+                            for c in self.mapper.cascade_iterator('delete', child):
+                                uowcommit.register_object(c, isdelete=True)
     def _synchronize(self, obj, child, associationrow, clearkeys):
         dest = associationrow
         source = None
index e770a4ec4228851b9cde24c4a3a56cd3ece9f62e..16453974b777602dd802f0adbe958487b990a4f9 100644 (file)
@@ -190,7 +190,7 @@ class M2MCascadeTest(testbase.AssertMixin):
         
     def tearDownAll(self):
         metadata.drop_all()
-    @testbase.supported('')
+
     def testdeleteorphan(self):
         class A(object):
             def __init__(self, data):
@@ -200,7 +200,7 @@ class M2MCascadeTest(testbase.AssertMixin):
                 self.data = data
         
         mapper(A, a, properties={
-            # if no backref here, delete-orphan fails
+            # if no backref here, delete-orphan failed until [ticket:427] was fixed
             'bs':relation(B, secondary=atob, cascade="all, delete-orphan")
         })
         mapper(B, b)
@@ -217,7 +217,32 @@ class M2MCascadeTest(testbase.AssertMixin):
         assert atob.count().scalar() ==0
         assert b.count().scalar() == 0
         assert a.count().scalar() == 1
+    
+    def testcascadedelete(self):
+        class A(object):
+            def __init__(self, data):
+                self.data = data
+        class B(object):
+            def __init__(self, data):
+                self.data = data
         
+        mapper(A, a, properties={
+            'bs':relation(B, secondary=atob, cascade="all, delete-orphan")
+        })
+        mapper(B, b)
+        
+        sess = create_session()
+        a1 = A('a1')
+        b1 = B('b1')
+        a1.bs.append(b1)
+        sess.save(a1)
+        sess.flush()
+        
+        sess.delete(a1)
+        sess.flush()
+        assert atob.count().scalar() ==0
+        assert b.count().scalar() == 0
+        assert a.count().scalar() == 0
         
 if __name__ == "__main__":
     testbase.main()