diff options
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/dependency.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/properties.py | 15 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/session.py | 5 |
3 files changed, 17 insertions, 7 deletions
diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py index 1a17e8599..707165215 100644 --- a/lib/sqlalchemy/orm/dependency.py +++ b/lib/sqlalchemy/orm/dependency.py @@ -388,8 +388,8 @@ class ManyToManyDP(DependencyProcessor): secondary_insert = [] secondary_update = [] - if hasattr(self.prop, 'reverse_property'): - reverse_dep = getattr(self.prop.reverse_property, '_dependency_processor', None) + if self.prop._reverse_property: + reverse_dep = getattr(self.prop._reverse_property, '_dependency_processor', None) else: reverse_dep = None diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index ca430378b..a7932bfc5 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -212,7 +212,8 @@ class PropertyLoader(StrategizedProperty): self.comparator = PropertyLoader.Comparator(self) self.join_depth = join_depth self.strategy_class = strategy_class - + self._reverse_property = None + if cascade is not None: self.cascade = CascadeOptions(cascade) else: @@ -349,17 +350,22 @@ class PropertyLoader(StrategizedProperty): return str(self.parent.class_.__name__) + "." + self.key + " (" + str(self.mapper.class_.__name__) + ")" def merge(self, session, source, dest, dont_load, _recursive): + if not dont_load and self._reverse_property and (source, self._reverse_property) in _recursive: + return + if not "merge" in self.cascade: # TODO: lazy callable should merge to the new instance dest._state.expire_attributes([self.key]) return + instances = attributes.get_as_list(source._state, self.key, passive=True) if not instances: return + if self.uselist: - # sets a blank collection according to the correct list class dest_list = attributes.init_collection(dest, self.key) for current in instances: + _recursive[(current, self)] = True obj = session.merge(current, entity_name=self.mapper.entity_name, dont_load=dont_load, _recursive=_recursive) if obj is not None: if dont_load: @@ -369,6 +375,7 @@ class PropertyLoader(StrategizedProperty): else: current = instances[0] if current is not None: + _recursive[(current, self)] = True obj = session.merge(current, entity_name=self.mapper.entity_name, dont_load=dont_load, _recursive=_recursive) if obj is not None: if dont_load: @@ -781,8 +788,8 @@ class BackRef(object): mapper._compile_property(self.key, relation); - prop.reverse_property = mapper._get_property(self.key) - mapper._get_property(self.key).reverse_property = prop + prop._reverse_property = mapper._get_property(self.key) + mapper._get_property(self.key)._reverse_property = prop else: raise exceptions.ArgumentError("Error creating backref '%s' on relation '%s': property of that name exists on mapper '%s'" % (self.key, prop, mapper)) diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 03471df34..b689b2441 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -949,7 +949,8 @@ class Session(object): """ if _recursive is None: - _recursive = {} #TODO: this should be an IdentityDict + _recursive = {} # TODO: this should be an IdentityDict for instances, but will need a separate + # dict for PropertyLoader tuples if entity_name is not None: mapper = _class_mapper(instance.__class__, entity_name=entity_name) else: @@ -959,6 +960,8 @@ class Session(object): key = getattr(instance, '_instance_key', None) if key is None: + if dont_load: + raise exceptions.InvalidRequestError("merge() with dont_load=True option does not support objects transient (i.e. unpersisted) objects. flush() all changes on mapped instances before merging with dont_load=True.") merged = attributes.new_instance(mapper.class_) else: if key in self.identity_map: |
