Commits

Anonymous committed e03fe56

Query.update() and Query.delete() should turn off eagerloads. Fixes #1378.

Comments (0)

Files changed (3)

       owned by an object being deleted would not be set to
       None if the relation() was self-referential. [ticket:1376]
 
+    - Fixed Query.update() and Query.delete() failures with eagerloaded
+      relations. [ticket:1378]
+
 - schema
     - Added a quote_schema() method to the IdentifierPreparer class
       so that dialects can override how schemas get handled. This

lib/sqlalchemy/orm/query.py

         if synchronize_session not in [False, 'evaluate', 'fetch']:
             raise sa_exc.ArgumentError("Valid strategies for session synchronization are False, 'evaluate' and 'fetch'")
 
+        self = self.enable_eagerloads(False)
+
         context = self._compile_context()
         if len(context.statement.froms) != 1 or not isinstance(context.statement.froms[0], schema.Table):
             raise sa_exc.ArgumentError("Only deletion via a single table query is currently supported")
         if synchronize_session not in [False, 'evaluate', 'expire']:
             raise sa_exc.ArgumentError("Valid strategies for session synchronization are False, 'evaluate' and 'expire'")
 
+        self = self.enable_eagerloads(False)
+
         context = self._compile_context()
         if len(context.statement.froms) != 1 or not isinstance(context.statement.froms[0], schema.Table):
             raise sa_exc.ArgumentError("Only update via a single table query is currently supported")

test/orm/query.py

               Column('id', Integer, primary_key=True),
               Column('name', String(32)),
               Column('age', Integer))
+
+        Table('documents', metadata,
+              Column('id', Integer, primary_key=True),
+              Column('user_id', None, ForeignKey('users.id')),
+              Column('title', String(32)))
     
     def setup_classes(self):
         class User(_base.ComparableEntity):
             pass
+
+        class Document(_base.ComparableEntity):
+            pass
     
     @testing.resolve_artifact_names
     def insert_data(self):
             dict(id=3, name='jill', age=29),
             dict(id=4, name='jane', age=37),
         ])
+
+    @testing.resolve_artifact_names
+    def insert_documents(self):
+        documents.insert().execute([
+            dict(id=1, user_id=1, title='foo'),
+            dict(id=2, user_id=1, title='bar'),
+            dict(id=3, user_id=2, title='baz'),
+        ])
     
     @testing.resolve_artifact_names
     def setup_mappers(self):
         mapper(User, users)
+        mapper(Document, documents, properties={
+            'user': relation(User, lazy=False, backref=backref('documents', lazy=True))
+        })
     
     @testing.resolve_artifact_names
     def test_delete(self):
         rowcount = sess.query(User).filter(User.age > 26).delete(synchronize_session=False)
         self.assertEquals(rowcount, 3)
 
+    @testing.resolve_artifact_names
+    def test_update_with_eager_relations(self):
+        self.insert_documents()
+
+        sess = create_session(bind=testing.db, autocommit=False)
+
+        foo,bar,baz = sess.query(Document).order_by(Document.id).all()
+        sess.query(Document).filter(Document.user_id == 1).update({'title': Document.title+Document.title}, synchronize_session='evaluate')
+
+        eq_([foo.title, bar.title, baz.title], ['foofoo','barbar', 'baz'])
+        eq_(sess.query(Document.title).order_by(Document.id).all(), zip(['foofoo','barbar', 'baz']))
+
+    @testing.resolve_artifact_names
+    def test_update_with_explicit_eagerload(self):
+        sess = create_session(bind=testing.db, autocommit=False)
+
+        john,jack,jill,jane = sess.query(User).order_by(User.id).all()
+        sess.query(User).options(eagerload(User.documents)).filter(User.age > 29).update({'age': User.age - 10}, synchronize_session='expire')
+
+        eq_([john.age, jack.age, jill.age, jane.age], [25,37,29,27])
+        eq_(sess.query(User.age).order_by(User.id).all(), zip([25,37,29,27]))
+
+    @testing.resolve_artifact_names
+    def test_delete_with_eager_relations(self):
+        self.insert_documents()
+
+        sess = create_session(bind=testing.db, autocommit=False)
+
+        sess.query(Document).filter(Document.user_id == 1).delete(synchronize_session=False)
+
+        eq_(sess.query(Document.title).all(), zip(['baz']))
+
 if __name__ == '__main__':
     testenv.main()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.