diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-10-27 09:51:50 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-10-27 09:51:50 -0400 |
| commit | e56a9d85acd165cfea08f9dc7e9d747054ce6fdb (patch) | |
| tree | 9b4945ac54be816787e58f9fe8745ef56e0a7690 /test | |
| parent | 1f32d014da5d40406cd5d3996be5283c2fc57b26 (diff) | |
| download | sqlalchemy-e56a9d85acd165cfea08f9dc7e9d747054ce6fdb.tar.gz | |
Restore object to the identity_map upon delete() unconditionally
Fixed regression caused by :ticket:`2677` whereby calling
:meth:`.Session.delete` on an object that was already flushed as
deleted in that session would fail to set up the object in the
identity map (or reject the object), causing flush errors as the
object were in a state not accommodated by the unit of work.
The pre-1.1 behavior in this case has been restored, which is that
the object is put back into the identity map so that the DELETE
statement will be attempted again, which emits a warning that the number
of expected rows was not matched (unless the row were restored outside
of the session).
Change-Id: I9a8871f82cb1ebe67a7ad54d888d5ee835a9a40a
Fixes: #3839
Diffstat (limited to 'test')
| -rw-r--r-- | test/orm/test_session.py | 33 | ||||
| -rw-r--r-- | test/orm/test_unitofworkv2.py | 20 |
2 files changed, 52 insertions, 1 deletions
diff --git a/test/orm/test_session.py b/test/orm/test_session.py index caeb08530..24666d084 100644 --- a/test/orm/test_session.py +++ b/test/orm/test_session.py @@ -1,5 +1,5 @@ from sqlalchemy.testing import eq_, assert_raises, \ - assert_raises_message + assert_raises_message, assertions from sqlalchemy.testing.util import gc_collect from sqlalchemy.testing import pickleable from sqlalchemy.util import pickle @@ -347,6 +347,37 @@ class SessionStateTest(_fixtures.FixtureTest): eq_(sess.query(User).count(), 1) + def test_deleted_adds_to_imap_unconditionally(self): + users, User = self.tables.users, self.classes.User + + mapper(User, users) + + sess = Session() + u1 = User(name='u1') + sess.add(u1) + sess.commit() + + sess.delete(u1) + sess.flush() + + # object is not in session + assert u1 not in sess + + # but it *is* attached + assert u1._sa_instance_state.session_id == sess.hash_key + + # mark as deleted again + sess.delete(u1) + + # in the session again + assert u1 in sess + + # commit proceeds w/ warning + with assertions.expect_warnings( + "DELETE statement on table 'users' " + r"expected to delete 1 row\(s\); 0 were matched."): + sess.commit() + def test_autoflush_expressions(self): """test that an expression which is dependent on object state is evaluated after the session autoflushes. This is the lambda diff --git a/test/orm/test_unitofworkv2.py b/test/orm/test_unitofworkv2.py index ae8454f6f..b2fefe616 100644 --- a/test/orm/test_unitofworkv2.py +++ b/test/orm/test_unitofworkv2.py @@ -1567,6 +1567,26 @@ class BasicStaleChecksTest(fixtures.MappedTest): ) @testing.requires.sane_multi_rowcount + def test_delete_twice(self): + Parent, Child = self._fixture() + sess = Session() + p1 = Parent(id=1, data=2, child=None) + sess.add(p1) + sess.commit() + + sess.delete(p1) + sess.flush() + + sess.delete(p1) + + assert_raises_message( + exc.SAWarning, + "DELETE statement on table 'parent' expected to " + "delete 1 row\(s\); 0 were matched.", + sess.commit + ) + + @testing.requires.sane_multi_rowcount def test_delete_multi_missing_warning(self): Parent, Child = self._fixture() sess = Session() |
