diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-01-24 21:31:23 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-01-24 21:31:23 -0500 |
| commit | a477f8a61ec60b2fc343d87aa30ef6595c77727d (patch) | |
| tree | a3768faf5fb9513cefebaa02f122bd1565f057ce /lib | |
| parent | b1df6fab53a0d740fe60f04e5c9ad01027ba59af (diff) | |
| download | sqlalchemy-a477f8a61ec60b2fc343d87aa30ef6595c77727d.tar.gz | |
the consideration of a pending object as
an "orphan" has been modified to more closely match the
behavior as that of persistent objects, which is that the object
is expunged from the :class:`.Session` as soon as it is
de-associated from any of its orphan-enabled parents. Previously,
the pending object would be expunged only if de-associated
from all of its orphan-enabled parents. The new flag ``legacy_is_orphan``
is added to :func:`.orm.mapper` which re-establishes the
legacy behavior. [ticket:2655]
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/orm/__init__.py | 26 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 25 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/properties.py | 2 |
3 files changed, 45 insertions, 8 deletions
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py index 0b035ef9b..e9dde3ca7 100644 --- a/lib/sqlalchemy/orm/__init__.py +++ b/lib/sqlalchemy/orm/__init__.py @@ -947,6 +947,32 @@ def mapper(class_, local_table=None, *args, **params): this parameter can be used to specify which columns are "foreign". In most cases can be left as ``None``. + :param legacy_is_orphan: Boolean, defaults to ``False``. + When ``True``, specifies that "legacy" orphan consideration + is to be applied to objects mapped by this mapper, which means + that a pending (that is, not persistent) object is auto-expunged + from an owning :class:`.Session` only when it is de-associated + from *all* parents that specify a ``delete-orphan`` cascade towards + this mapper. The new default behavior is that the object is auto-expunged + when it is de-associated with *any* of its parents that specify + ``delete-orphan`` cascade. This behavior is more consistent with + that of a persistent object, and allows behavior to be consistent + in more scenarios independently of whether or not an orphanable + object has been flushed yet or not. + + See the change note and example at :ref:`legacy_is_orphan_addition` + for more detail on this change. + + .. versionadded:: 0.8 - the consideration of a pending object as + an "orphan" has been modified to more closely match the + behavior as that of persistent objects, which is that the object + is expunged from the :class:`.Session` as soon as it is + de-associated from any of its orphan-enabled parents. Previously, + the pending object would be expunged only if de-associated + from all of its orphan-enabled parents. The new flag ``legacy_is_orphan`` + is added to :func:`.orm.mapper` which re-establishes the + legacy behavior. + :param non_primary: Specify that this :class:`.Mapper` is in addition to the "primary" mapper, that is, the one used for persistence. The :class:`.Mapper` created here may be used for ad-hoc diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index eb43cc53e..447a5fce1 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -113,6 +113,7 @@ class Mapper(_InspectionAttr): exclude_properties=None, passive_updates=True, eager_defaults=False, + legacy_is_orphan=False, _compiled_cache_size=100, ): """Construct a new mapper. @@ -145,7 +146,7 @@ class Mapper(_InspectionAttr): self.inherit_condition = inherit_condition self.inherit_foreign_keys = inherit_foreign_keys self._init_properties = properties or {} - self.delete_orphans = [] + self._delete_orphans = [] self.batch = batch self.eager_defaults = eager_defaults self.column_prefix = column_prefix @@ -154,6 +155,7 @@ class Mapper(_InspectionAttr): self._dependency_processors = [] self.validators = util.immutabledict() self.passive_updates = passive_updates + self.legacy_is_orphan = legacy_is_orphan self._clause_adapter = None self._requires_row_aliasing = False self._inherits_equated_pairs = None @@ -1292,14 +1294,23 @@ class Mapper(_InspectionAttr): ) def _is_orphan(self, state): - o = False + orphan_possible = False for mapper in self.iterate_to_root(): - for (key, cls) in mapper.delete_orphans: - if attributes.manager_of_class(cls).has_parent( - state, key, optimistic=bool(state.key)): + for (key, cls) in mapper._delete_orphans: + orphan_possible = True + + has_parent = attributes.manager_of_class(cls).has_parent( + state, key, optimistic=state.has_identity) + + if self.legacy_is_orphan and has_parent: return False - o = o or bool(mapper.delete_orphans) - return o + elif not self.legacy_is_orphan and not has_parent: + return True + + if self.legacy_is_orphan: + return orphan_possible + else: + return False def has_property(self, key): return key in self._props diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index bc238d973..c618e89b2 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -1081,7 +1081,7 @@ class RelationshipProperty(StrategizedProperty): self.target = self.mapper.mapped_table if self.cascade.delete_orphan: - self.mapper.primary_mapper().delete_orphans.append( + self.mapper.primary_mapper()._delete_orphans.append( (self.key, self.parent.class_) ) |
