]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- merge() includes a keyword argument "dont_load=True". setting this flag will cause
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 2 Nov 2007 17:58:20 +0000 (17:58 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 2 Nov 2007 17:58:20 +0000 (17:58 +0000)
the merge operation to not load any data from the database in response to incoming
detached objects, and will accept the incoming detached object as though it were
already present in that session.  Use this to merge detached objects from external
caching systems into the session.

CHANGES
lib/sqlalchemy/orm/properties.py
lib/sqlalchemy/orm/session.py
test/orm/merge.py

diff --git a/CHANGES b/CHANGES
index 81adb1e8e10ea948a1c599ecd82d53447f7bca93..c04dfe8ed6a7a731d461d0fe34316069562144b2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -81,6 +81,12 @@ CHANGES
       e.g. if you pickle a series of objects and unpickle (i.e. as in a Pylons HTTP session
       or similar), they can go into a new session without any conflict
 
+    - merge() includes a keyword argument "dont_load=True".  setting this flag will cause
+      the merge operation to not load any data from the database in response to incoming
+      detached objects, and will accept the incoming detached object as though it were 
+      already present in that session.  Use this to merge detached objects from external 
+      caching systems into the session.
+      
 0.4.0
 -----
 
index 6967b5e3505bf9091bcf24f3c904fe4640cea1cd..1e6be1f7df942813f93c0b38e56f6a63eddf02ed 100644 (file)
@@ -61,7 +61,7 @@ class ColumnProperty(StrategizedProperty):
     def get_history(self, obj, passive=False):
         return sessionlib.attribute_manager.get_history(obj, self.key, passive=passive)
 
-    def merge(self, session, source, dest, _recursive):
+    def merge(self, session, source, dest, dont_load, _recursive):
         setattr(dest, self.key, getattr(source, self.key, None))
 
     def get_col_value(self, column, value):
@@ -280,7 +280,7 @@ class PropertyLoader(StrategizedProperty):
     def __str__(self):
         return str(self.parent.class_.__name__) + "." + self.key + " (" + str(self.mapper.class_.__name__)  + ")"
 
-    def merge(self, session, source, dest, _recursive):
+    def merge(self, session, source, dest, dont_load, _recursive):
         if not "merge" in self.cascade or self.mapper in _recursive:
             return
         childlist = sessionlib.attribute_manager.get_history(source, self.key, passive=True)
@@ -290,14 +290,14 @@ class PropertyLoader(StrategizedProperty):
             # sets a blank collection according to the correct list class
             dest_list = sessionlib.attribute_manager.init_collection(dest, self.key)
             for current in list(childlist):
-                obj = session.merge(current, entity_name=self.mapper.entity_name, _recursive=_recursive)
+                obj = session.merge(current, entity_name=self.mapper.entity_name, dont_load=dont_load, _recursive=_recursive)
                 if obj is not None:
                     #dest_list.append_without_event(obj)
                     dest_list.append_with_event(obj)
         else:
             current = list(childlist)[0]
             if current is not None:
-                obj = session.merge(current, entity_name=self.mapper.entity_name, _recursive=_recursive)
+                obj = session.merge(current, entity_name=self.mapper.entity_name, dont_load=dont_load, _recursive=_recursive)
                 if obj is not None:
                     setattr(dest, self.key, obj)
 
index 6be72ecefee0d30abb0fb984df14a66ba32b3be4..30e97eba7c66f64606c2548e3e9f497233faaf92 100644 (file)
@@ -837,7 +837,7 @@ class Session(object):
             self._delete_impl(c, ignore_transient=True)
 
 
-    def merge(self, object, entity_name=None, _recursive=None):
+    def merge(self, object, entity_name=None, dont_load=False, _recursive=None):
         """Copy the state of the given `object` onto the persistent
         object with the same identifier.
 
@@ -868,12 +868,17 @@ class Session(object):
             else:
                 if key in self.identity_map:
                     merged = self.identity_map[key]
+                elif dont_load:
+                    merged = attribute_manager.new_instance(mapper.class_)
+                    merged._instance_key = key
+                    self.update(merged, entity_name=mapper.entity_name)
+                    merged._state.committed_state = object._state.committed_state.copy()
                 else:
                     merged = self.get(mapper.class_, key[1])
                     if merged is None:
                         raise exceptions.AssertionError("Instance %s has an instance key but is not persisted" % mapperutil.instance_str(object))
             for prop in mapper.iterate_properties:
-                prop.merge(self, object, merged, _recursive)
+                prop.merge(self, object, merged, dont_load, _recursive)
             if key is None:
                 self.save(merged, entity_name=mapper.entity_name)
             return merged
index 3dd0a95a47fd5e5d9dd8f3c9d390c2a36390b671..7f45c56a2dafdea99baca227708f845989e1063c 100644 (file)
@@ -101,6 +101,22 @@ class MergeTest(AssertMixin):
         u = sess.query(User).get(7)
         self.assert_result([u], User, {'user_id':7, 'user_name':'fred2', 'addresses':(Address, [{'email_address':'foo@bar.com'}, {'email_address':'hoho@lalala.com'}])})
 
+        # merge persistent object into another session
+        sess4 = create_session()
+        u = sess4.merge(u)
+        def go():
+            sess4.flush()
+        # no changes; therefore flush should do nothing
+        self.assert_sql_count(testbase.db, go, 0)
+        
+        # test with "dontload" merge
+        sess5 = create_session()
+        u = sess5.merge(u, dont_load=True)
+        def go():
+            sess5.flush()
+        # no changes; therefore flush should do nothing
+        self.assert_sql_count(testbase.db, go, 0)
+
     def test_saved_cascade_2(self):
         """tests a more involved merge"""
         mapper(Order, orders, properties={
@@ -141,27 +157,28 @@ class MergeTest(AssertMixin):
         assert o2.customer.user_name == 'also fred'
         
     def test_saved_cascade_3(self):
-            """test merge of a persistent entity with one_to_one relationship"""
-            mapper(User, users, properties={
-                'address':relation(mapper(Address, addresses),uselist = False)
-            })
-            sess = create_session()
-            u = User()
-            u.user_id = 7
-            u.user_name = "fred"
-            a1 = Address()
-            a1.email_address='foo@bar.com'
-            u.address = a1
+        """test merge of a persistent entity with one_to_one relationship"""
 
-            sess.save(u)
-            sess.flush()
+        mapper(User, users, properties={
+            'address':relation(mapper(Address, addresses),uselist = False)
+        })
+        sess = create_session()
+        u = User()
+        u.user_id = 7
+        u.user_name = "fred"
+        a1 = Address()
+        a1.email_address='foo@bar.com'
+        u.address = a1
 
-            sess2 = create_session()
-            u2 = sess2.query(User).get(7)
-            u2.user_name = 'fred2'
-            u2.address.email_address = 'hoho@lalala.com'
+        sess.save(u)
+        sess.flush()
+
+        sess2 = create_session()
+        u2 = sess2.query(User).get(7)
+        u2.user_name = 'fred2'
+        u2.address.email_address = 'hoho@lalala.com'
 
-            u3 = sess.merge(u2)
+        u3 = sess.merge(u2)
         
 if __name__ == "__main__":    
     testbase.main()