diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-01-13 01:39:15 +0000 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-01-13 01:39:15 +0000 |
| commit | 5b4871f4364c7b93de010097aa8f4008f69bddd4 (patch) | |
| tree | f1febf6ffff2881ea0be5f5a627e6b3f392bfe49 /lib/sqlalchemy | |
| parent | 29dd5916496ac93bd81a7f2986563ff6160e0a51 (diff) | |
| download | sqlalchemy-5b4871f4364c7b93de010097aa8f4008f69bddd4.tar.gz | |
- basic idea of "session.merge()" actually implemented. needs more testing.
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/interfaces.py | 5 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/properties.py | 18 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/session.py | 40 |
3 files changed, 41 insertions, 22 deletions
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index 0c0ad2a72..4e9fe55f4 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -55,7 +55,10 @@ class MapperProperty(object): This flag is used to indicate that the MapperProperty can define attribute instrumentation for the class at the class level (as opposed to the individual instance level.)""" return self.parent._is_primary_mapper() - + def merge(self, session, source, dest): + """merges the attribute represented by this MapperProperty from source to destination object""" + raise NotImplementedError() + class StrategizedProperty(MapperProperty): """a MapperProperty which uses selectable strategies to affect loading behavior. There is a single default strategy selected, and alternate strategies can be selected diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index cdab5464a..888ac0442 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -39,6 +39,8 @@ class SynonymProperty(MapperProperty): return s return getattr(obj, self.name) setattr(self.parent.class_, self.key, SynonymProp()) + def merge(self, session, source, dest): + pass class ColumnProperty(StrategizedProperty): """describes an object attribute that corresponds to a table column.""" @@ -60,6 +62,8 @@ class ColumnProperty(StrategizedProperty): setattr(object, self.key, value) def get_history(self, obj, passive=False): return sessionlib.attribute_manager.get_history(obj, self.key, passive=passive) + def merge(self, session, source, dest): + setattr(dest, self.key, getattr(source, self.key, None)) ColumnProperty.logger = logging.class_logger(ColumnProperty) @@ -118,6 +122,20 @@ class PropertyLoader(StrategizedProperty): def __str__(self): return self.__class__.__name__ + " " + str(self.parent) + "->" + self.key + "->" + str(self.mapper) + + def merge(self, session, source, dest): + if not "merge" in self.cascade: + return + childlist = sessionlib.attribute_manager.get_history(source, self.key, passive=True) + if childlist is None: + return + if self.uselist: + # sets a blank list according to the correct list class + dest_list = getattr(self.parent.class_, self.key).initialize(dest) + for current in list(childlist): + dest_list.append(session.merge(current)) + else: + setattr(dest, self.key, session.merge(current)) def cascade_iterator(self, type, object, recursive, halt_on=None): if not type in self.cascade: diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 113341e17..829220688 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -324,29 +324,27 @@ class Session(object): self.uow.register_deleted(c) def merge(self, object, entity_name=None): - """merge the object into a newly loaded or existing instance from this Session. + """copy the state of the given object onto the persistent object with the same identifier. - note: this method is currently not completely implemented.""" - instance = None - for obj in [object] + list(_object_mapper(object).cascade_iterator('merge', object)): - key = getattr(obj, '_instance_key', None) - if key is None: - mapper = _object_mapper(object) - ident = mapper.identity(object) - for k in ident: - if k is None: - raise exceptions.InvalidRequestError("Instance '%s' does not have a full set of identity values, and does not represent a saved entity in the database. Use the add() method to add unsaved instances to this Session." % repr(obj)) - key = mapper.identity_key(ident) - u = self.uow - if u.identity_map.has_key(key): - # TODO: copy the state of the given object into this one. tricky ! - inst = u.identity_map[key] + If there is no persistent instance currently associated with the session, it will be loaded. + Return the persistent instance. If the given instance is unsaved, save a copy of and return it as + a newly persistent instance. The given instance does not become associated with the session. + This operation cascades to associated instances if the association is mapped with cascade="merge". + """ + mapper = _object_mapper(object) + key = getattr(object, '_instance_key', None) + if key is None: + merged = mapper._create_instance(self) + else: + if key in self.identity_map: + merged = self.identity_map[key] else: - inst = self.get(object.__class__, key[1]) - if obj is object: - instance = inst - - return instance + merged = self.get(mapper.class_, key[1]) + for prop in mapper.props.values(): + prop.merge(self, object, merged) + if key is None: + self.save(merged) + return merged def _save_impl(self, object, **kwargs): if hasattr(object, '_instance_key'): |
