summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2019-11-22 10:27:02 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2019-11-22 11:15:56 -0500
commitff4b63c2bc5f118d5ec1aacff06708dbc08a37a7 (patch)
treedcc0abac283a66f834153034a26efc67657ef1b6
parent1bf1a9c0d8e122da79898835c007ea904e238c21 (diff)
downloadsqlalchemy-ff4b63c2bc5f118d5ec1aacff06708dbc08a37a7.tar.gz
Don't raise w/ raiseload strategy for many-to-one history in flush
Fixed issue involving ``lazy="raise"`` strategy where an ORM delete of an object would raise for a simple "use-get" style many-to-one relationship that had lazy="raise" configured. This is inconsistent vs. the change introduced in 1.3 as part of :ticket:`4353`, where it was established that a history operation that does not expect emit SQL should bypass the ``lazy="raise"`` check, and instead effectively treat it as ``lazy="raise_on_sql"`` for this case. The fix adjusts the lazy loader strategy to not raise for the case where the lazy load was instructed that it should not emit SQL if the object were not present. Fixes: #4997 Change-Id: I4deb8c129900f28321c4a5c48301db5fe2aedf78
-rw-r--r--doc/build/changelog/unreleased_13/4997.rst13
-rw-r--r--lib/sqlalchemy/orm/strategies.py25
-rw-r--r--test/orm/test_relationships.py11
3 files changed, 45 insertions, 4 deletions
diff --git a/doc/build/changelog/unreleased_13/4997.rst b/doc/build/changelog/unreleased_13/4997.rst
new file mode 100644
index 000000000..f58caf043
--- /dev/null
+++ b/doc/build/changelog/unreleased_13/4997.rst
@@ -0,0 +1,13 @@
+.. change::
+ :tags: bug, orm
+ :tickets: 4997
+
+ Fixed issue involving ``lazy="raise"`` strategy where an ORM delete of an
+ object would raise for a simple "use-get" style many-to-one relationship
+ that had lazy="raise" configured. This is inconsistent vs. the change
+ introduced in 1.3 as part of :ticket:`4353`, where it was established that
+ a history operation that does not expect emit SQL should bypass the
+ ``lazy="raise"`` check, and instead effectively treat it as
+ ``lazy="raise_on_sql"`` for this case. The fix adjusts the lazy loader
+ strategy to not raise for the case where the lazy load was instructed that
+ it should not emit SQL if the object were not present.
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 44ef43418..38d379a4c 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -561,9 +561,11 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
self.is_aliased_class = inspect(self.entity).is_aliased_class
join_condition = self.parent_property._join_condition
- self._lazywhere, self._bind_to_col, self._equated_columns = (
- join_condition.create_lazy_clause()
- )
+ (
+ self._lazywhere,
+ self._bind_to_col,
+ self._equated_columns,
+ ) = join_condition.create_lazy_clause()
(
self._rev_lazywhere,
@@ -708,7 +710,22 @@ class LazyLoader(AbstractRelationshipLoader, util.MemoizedSlots):
):
return attributes.PASSIVE_NO_RESULT
- if self._raise_always and not passive & attributes.NO_RAISE:
+ if (
+ # we were given lazy="raise"
+ self._raise_always
+ # the no_raise history-related flag was not passed
+ and not passive & attributes.NO_RAISE
+ and (
+ # if we are use_get and related_object_ok is disabled,
+ # which means we are at most looking in the identity map
+ # for history purposes or otherwise returning
+ # PASSIVE_NO_RESULT, don't raise. This is also a
+ # history-related flag
+ not self.use_get
+ or passive & attributes.RELATED_OBJECT_OK
+ )
+ ):
+
self._invoke_raise_load(state, passive, "raise")
session = _state_session(state)
diff --git a/test/orm/test_relationships.py b/test/orm/test_relationships.py
index 30c7c9c04..8d5d87f90 100644
--- a/test/orm/test_relationships.py
+++ b/test/orm/test_relationships.py
@@ -5355,6 +5355,17 @@ class InactiveHistoryNoRaiseTest(_fixtures.FixtureTest):
s.commit()
+ eq_(s.query(Address).count(), 1)
+ eq_(s.query(User).count(), 1)
+
+ # test for issue #4997
+ # delete of Address should proceed, as User object does not
+ # need to be loaded
+ s.delete(a1)
+ s.commit()
+ eq_(s.query(Address).count(), 0)
+ eq_(s.query(User).count(), 1)
+
class RelationDeprecationTest(fixtures.MappedTest):