diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-12-04 11:52:16 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-12-04 11:52:16 -0500 |
commit | 3ec9b9f6b601b8ef69d4978c7182e8efedefd191 (patch) | |
tree | fded91038e426b974d141f2a4e4be714a18d0ae2 /lib/sqlalchemy/orm/session.py | |
parent | 935bc34dc50d5e4bdf181a8287d6e4cdbde073d0 (diff) | |
download | sqlalchemy-3ec9b9f6b601b8ef69d4978c7182e8efedefd191.tar.gz |
- The :meth:`.Session.merge` method now tracks pending objects by
primary key before emitting an INSERT, and merges distinct objects with
duplicate primary keys together as they are encountered, which is
essentially semi-deterministic at best. This behavior
matches what happens already with persistent objects.
fixes #3601
Diffstat (limited to 'lib/sqlalchemy/orm/session.py')
-rw-r--r-- | lib/sqlalchemy/orm/session.py | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 4272d7d78..f58e4de61 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -1689,6 +1689,10 @@ class Session(_SessionClassMethods): See :ref:`unitofwork_merging` for a detailed discussion of merging. + .. versionchanged:: 1.1 - :meth:`.Session.merge` will now reconcile + pending objects with overlapping primary keys in the same way + as persistent. See :ref:`change_3601` for discussion. + :param instance: Instance to be merged. :param load: Boolean, when False, :meth:`.merge` switches into a "high performance" mode which causes it to forego emitting history @@ -1713,12 +1717,14 @@ class Session(_SessionClassMethods): should be "clean" as well, else this suggests a mis-use of the method. + """ if self._warn_on_events: self._flush_warning("Session.merge()") _recursive = {} + _resolve_conflict_map = {} if load: # flush current contents if we expect to load data @@ -1731,11 +1737,13 @@ class Session(_SessionClassMethods): return self._merge( attributes.instance_state(instance), attributes.instance_dict(instance), - load=load, _recursive=_recursive) + load=load, _recursive=_recursive, + _resolve_conflict_map=_resolve_conflict_map) finally: self.autoflush = autoflush - def _merge(self, state, state_dict, load=True, _recursive=None): + def _merge(self, state, state_dict, load=True, _recursive=None, + _resolve_conflict_map=None): mapper = _state_mapper(state) if state in _recursive: return _recursive[state] @@ -1751,9 +1759,14 @@ class Session(_SessionClassMethods): "all changes on mapped instances before merging with " "load=False.") key = mapper._identity_key_from_state(state) + key_is_persistent = attributes.NEVER_SET not in key[1] + else: + key_is_persistent = True if key in self.identity_map: merged = self.identity_map[key] + elif key_is_persistent and key in _resolve_conflict_map: + merged = _resolve_conflict_map[key] elif not load: if state.modified: @@ -1785,6 +1798,7 @@ class Session(_SessionClassMethods): merged_dict = attributes.instance_dict(merged) _recursive[state] = merged + _resolve_conflict_map[key] = merged # check that we didn't just pull the exact same # state out. @@ -1823,7 +1837,7 @@ class Session(_SessionClassMethods): for prop in mapper.iterate_properties: prop.merge(self, state, state_dict, merged_state, merged_dict, - load, _recursive) + load, _recursive, _resolve_conflict_map) if not load: # remove any history |