diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2008-09-05 17:16:11 +0000 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2008-09-05 17:16:11 +0000 |
| commit | f3cca5255b6dfaa0771a443c0119f5463ce9d56f (patch) | |
| tree | d516fbd8605cf6bd32beba765c6f07f93c345ad9 /lib | |
| parent | 0fbb67b71a91a1c6f792812474f45a52333aa227 (diff) | |
| download | sqlalchemy-f3cca5255b6dfaa0771a443c0119f5463ce9d56f.tar.gz | |
- rearranged delete() so that the object is attached before
cascades fire off [ticket:5058]
- after_attach() only fires if the object was not previously attached
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/orm/session.py | 66 |
1 files changed, 37 insertions, 29 deletions
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index f2d4e150a..66009be01 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -1144,12 +1144,28 @@ class Session(object): except exc.NO_STATE: raise exc.UnmappedInstanceError(instance) - # grab the full cascade list first, since lazyloads/autoflush - # may be triggered by this operation (delete cascade lazyloads by default) + if state.key is None: + raise sa_exc.InvalidRequestError( + "Instance '%s' is not persisted" % + mapperutil.state_str(state)) + + if state in self._deleted: + return + + # ensure object is attached to allow the + # cascade operation to load deferred attributes + # and collections + self._attach(state) + + # grab the cascades before adding the item to the deleted list + # so that autoflush does not delete the item cascade_states = list(_cascade_state_iterator('delete', state)) - self._delete_impl(state) + + self._deleted[state] = state.obj() + self.identity_map.add(state) + for state, m, o in cascade_states: - self._delete_impl(state, ignore_transient=True) + self._delete_impl(state) def merge(self, instance, dont_load=False, _recursive=None): @@ -1252,18 +1268,12 @@ class Session(object): if (self.identity_map.contains_state(state) and state not in self._deleted): return + if state.key is None: raise sa_exc.InvalidRequestError( "Instance '%s' is not persisted" % mapperutil.state_str(state)) - if (state.key in self.identity_map and - not self.identity_map.contains_state(state)): - raise sa_exc.InvalidRequestError( - "Could not update instance '%s', identity key %s; a different " - "instance with the same identity key already exists in this " - "session." % (mapperutil.state_str(state), state.key)) - self._attach(state) self._deleted.pop(state, None) self.identity_map.add(state) @@ -1274,38 +1284,36 @@ class Session(object): else: self._update_impl(state) - def _delete_impl(self, state, ignore_transient=False): - if self.identity_map.contains_state(state) and state in self._deleted: + def _delete_impl(self, state): + if state in self._deleted: return if state.key is None: - if ignore_transient: - return - else: - raise sa_exc.InvalidRequestError( - "Instance '%s' is not persisted" % - mapperutil.state_str(state)) - if (state.key in self.identity_map and - not self.identity_map.contains_state(state)): - raise sa_exc.InvalidRequestError( - "Instance '%s' is with key %s already persisted with a " - "different identity" % (mapperutil.state_str(state), - state.key)) - + return + self._attach(state) self._deleted[state] = state.obj() self.identity_map.add(state) - + def _attach(self, state): + if state.key and \ + state.key in self.identity_map and \ + not self.identity_map.contains_state(state): + raise sa_exc.InvalidRequestError( + "Can't attach instance %s; another instance with key %s is already present in this session." % + (mapperutil.state_str(state), state.key) + ) + if state.session_id and state.session_id is not self.hash_key: raise sa_exc.InvalidRequestError( "Object '%s' is already attached to session '%s' " "(this is '%s')" % (mapperutil.state_str(state), state.session_id, self.hash_key)) + if state.session_id != self.hash_key: state.session_id = self.hash_key - for ext in self.extensions: - ext.after_attach(self, state.obj()) + for ext in self.extensions: + ext.after_attach(self, state.obj()) def __contains__(self, instance): """Return True if the instance is associated with this session. |
