]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- relation() with uselist=False will emit a warning when
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 18 Dec 2009 17:24:20 +0000 (17:24 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 18 Dec 2009 17:24:20 +0000 (17:24 +0000)
an eager load locates more than one valid value for the row,
typically due to primaryjoin/secondaryjoin conditions which
aren't appropriate for LEFT OUTER JOIN.  [ticket:1643]

CHANGES
lib/sqlalchemy/orm/strategies.py
test/orm/test_eager_relations.py

diff --git a/CHANGES b/CHANGES
index 079814e038040200fd57ba7b9afa5d5a84d66059..2fa791be19210e137f0db8d5badb7171b93060e1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -69,6 +69,11 @@ CHANGES
     in filter criterion against the dynamic relation.
     [ticket:1531]
 
+  - relation() with uselist=False will emit a warning when 
+    an eager load locates more than one valid value for the row,
+    typically due to primaryjoin/secondaryjoin conditions which
+    aren't appropriate for LEFT OUTER JOIN.  [ticket:1643]
+    
   - an explicit check occurs when a synonym() is used with 
     map_column=True, when a ColumnProperty (deferred or otherwise)
     exists separately in the properties dictionary sent to mapper
index 7c56e1182af50084e422a1a9bfb80a92fff17d31..01da0f23a4703bc929947f0c41eb316322a3524f 100644 (file)
@@ -794,7 +794,13 @@ class EagerLoader(AbstractRelationLoader):
                     else:
                         # call _instance on the row, even though the object has been created,
                         # so that we further descend into properties
-                        _instance(row, None)
+                        existing = _instance(row, None)
+                        if existing is not None \
+                            and key in dict_ \
+                            and existing is not dict_[key]:
+                            util.warn(
+                                "Multiple rows returned with "
+                                "uselist=False for eagerly-loaded attribute '%s' " % self)
             else:
                 def execute(state, dict_, row, isnew, **flags):
                     if isnew or (state, key) not in context.attributes:
index a97c2fb2421e8f56151edcf819cb05bd3fe9d7a1..88871426fb5bf6b3ddd35cbfb0abc1f8e43ee026 100644 (file)
@@ -7,7 +7,7 @@ from sqlalchemy.orm import eagerload, deferred, undefer, eagerload_all, backref
 from sqlalchemy import Integer, String, Date, ForeignKey, and_, select, func
 from sqlalchemy.test.schema import Table, Column
 from sqlalchemy.orm import mapper, relation, create_session, lazyload, aliased
-from sqlalchemy.test.testing import eq_
+from sqlalchemy.test.testing import eq_, assert_raises
 from sqlalchemy.test.assertsql import CompiledSQL
 from test.orm import _base, _fixtures
 from sqlalchemy.util import OrderedDict as odict
@@ -774,6 +774,17 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL):
             ], q.order_by(User.id).all())
         self.assert_sql_count(testing.db, go, 1)
 
+    @testing.resolve_artifact_names 
+    def test_uselist_false_warning(self):
+        """test that multiple rows received by a uselist=False raises a warning."""
+        
+        mapper(User, users, properties={
+            'order':relation(Order, uselist=False)
+        })
+        mapper(Order, orders)
+        s = create_session()
+        assert_raises(sa.exc.SAWarning, s.query(User).options(eagerload(User.order)).all)
+        
     @testing.resolve_artifact_names
     def test_wide(self):
         mapper(Order, orders, properties={'items':relation(Item, secondary=order_items, lazy=False,