]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- merge -r6534 of trunk, for [ticket:1618]
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 7 Dec 2009 22:51:19 +0000 (22:51 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 7 Dec 2009 22:51:19 +0000 (22:51 +0000)
- backported 0.6's approach to "null pks allowed" in mapper._instance_processor

CHANGES
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/session.py
test/orm/test_merge.py

diff --git a/CHANGES b/CHANGES
index d0401f6329c25b685278e4effd87b703a8c6cc8c..0189b06567fc9b8a414c6900336a9821cfa1292f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -129,6 +129,10 @@ CHANGES
       would populate the related object's "subclass" table with
       data from the "subclass" table of the parent.
       [ticket:1485]
+    
+    - Fixed a needless select which would occur when merging
+      transient objects that contained a null primary key
+      identifier.  [ticket:1618]
       
     - relations() now have greater ability to be "overridden",
       meaning a subclass that explicitly specifies a relation()
index fd6d3a4a714bc0521257f24987d833dea5b9ca56..07cc7aaeb30b11d12628ba50d6ef9cdaf60f6a42 100644 (file)
@@ -41,6 +41,7 @@ __all__ = (
 _mapper_registry = weakref.WeakKeyDictionary()
 _new_mappers = False
 _already_compiling = False
+_none_set = frozenset([None])
 
 # a list of MapperExtensions that will be installed in all mappers by default
 global_extensions = []
@@ -1684,10 +1685,7 @@ class Mapper(object):
                     self._log_debug("_instance(): identity key %s not in session" % (identitykey,))
 
                 if self.allow_null_pks:
-                    for x in identitykey[1]:
-                        if x is not None:
-                            break
-                    else:
+                    if _none_set.issuperset(identitykey[1]):
                         return None
                 else:
                     if None in identitykey[1]:
index 914da874d5d6029a31b5c1818d2a7afb0646e20a..3dea2f6a3ddcf8b51a44d36ddcf54e71502dd53a 100644 (file)
@@ -19,7 +19,7 @@ from sqlalchemy.orm.util import class_mapper as _class_mapper
 from sqlalchemy.orm.util import (
     _class_to_mapper, _state_has_identity, _state_mapper,
     )
-from sqlalchemy.orm.mapper import Mapper
+from sqlalchemy.orm.mapper import Mapper, _none_set
 from sqlalchemy.orm.unitofwork import UOWTransaction
 from sqlalchemy.orm import identity
 
@@ -1173,7 +1173,7 @@ class Session(object):
         new_instance = False
         state = attributes.instance_state(instance)
         key = state.key
-
+        
         if key is None:
             if dont_load:
                 raise sa_exc.InvalidRequestError(
@@ -1183,24 +1183,24 @@ class Session(object):
                     "dont_load=True.")
             key = mapper._identity_key_from_state(state)
 
-        merged = None
-        if key:
-            if key in self.identity_map:
-                merged = self.identity_map[key]
-            elif dont_load:
-                if state.modified:
-                    raise sa_exc.InvalidRequestError(
-                        "merge() with dont_load=True option does not support "
-                        "objects marked as 'dirty'.  flush() all changes on "
-                        "mapped instances before merging with dont_load=True.")
-                merged = mapper.class_manager.new_instance()
-                merged_state = attributes.instance_state(merged)
-                merged_state.key = key
-                self._update_impl(merged_state)
-                new_instance = True
-            else:
-                merged = self.query(mapper.class_).get(key[1])
-
+        if key in self.identity_map:
+            merged = self.identity_map[key]
+        elif dont_load:
+            if state.modified:
+                raise sa_exc.InvalidRequestError(
+                    "merge() with dont_load=True option does not support "
+                    "objects marked as 'dirty'.  flush() all changes on "
+                    "mapped instances before merging with dont_load=True.")
+            merged = mapper.class_manager.new_instance()
+            merged_state = attributes.instance_state(merged)
+            merged_state.key = key
+            self._update_impl(merged_state)
+            new_instance = True
+        elif not _none_set.issuperset(key[1]):
+            merged = self.query(mapper.class_).get(key[1])
+        else:
+            merged = None
+            
         if merged is None:
             merged = mapper.class_manager.new_instance()
             merged_state = attributes.instance_state(merged)
index f4e3872b06a83d2a6f3144640487998de17b2b8e..d0f667237cf58e50fa91c9cec44abcd651416e07 100644 (file)
@@ -41,6 +41,16 @@ class MergeTest(_fixtures.FixtureTest):
         sess.expunge_all()
         eq_(sess.query(User).first(), User(id=7, name='fred'))
 
+    @testing.resolve_artifact_names
+    def test_transient_to_pending_no_pk(self):
+        """test that a transient object with no PK attribute doesn't trigger a needless load."""
+        mapper(User, users)
+        sess = create_session()
+        u = User(name='fred')
+        def go():
+            sess.merge(u)
+        self.assert_sql_count(testing.db, go, 0)
+        
     @testing.resolve_artifact_names
     def test_transient_to_pending_collection(self):
         mapper(User, users, properties={