summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-10-30 18:04:00 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-10-30 18:04:00 +0000
commit206c0b9792b02a0d77d92e679952cb2d0465cede (patch)
tree9927d4f396f1f3d99982ef9e2dab40753f74d970 /lib/sqlalchemy
parentadcf8ea00dda6d8e62fceeab36d90eabe36b5f91 (diff)
downloadsqlalchemy-206c0b9792b02a0d77d92e679952cb2d0465cede.tar.gz
- fix to "row switch" behavior, i.e. when an INSERT/DELETE is combined into a
single UPDATE; many-to-many relations on the parent object update properly. [ticket:841] - it's an error to session.save() an object which is already persistent [ticket:840] - changed a bunch of repr(obj) calls in session.py exceptions to use mapperutil.instance_str()
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/mapper.py2
-rw-r--r--lib/sqlalchemy/orm/session.py17
-rw-r--r--lib/sqlalchemy/orm/unitofwork.py13
3 files changed, 21 insertions, 11 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 2f3c36515..94ef04300 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -968,7 +968,7 @@ class Mapper(object):
raise exceptions.FlushError("New instance %s with identity key %s conflicts with persistent instance %s" % (mapperutil.instance_str(obj), str(instance_key), mapperutil.instance_str(existing)))
if self.__should_log_debug:
self.__log_debug("detected row switch for identity %s. will update %s, remove %s from transaction" % (instance_key, mapperutil.instance_str(obj), mapperutil.instance_str(existing)))
- uowtransaction.unregister_object(existing)
+ uowtransaction.set_row_switch(existing)
if has_identity(obj):
if obj._instance_key != instance_key:
raise exceptions.FlushError("Can't change the identity of instance %s in session (existing identity: %s; new identity: %s)" % (mapperutil.instance_str(obj), obj._instance_key, instance_key))
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 04aaa1209..42ad30b6a 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -631,6 +631,8 @@ class Session(object):
if self.bind is not None:
return self.bind
+ elif mapper is None:
+ raise exceptions.InvalidRequestError("Could not locate any mapper associated with SQL expression")
else:
if isinstance(mapper, type):
mapper = _class_mapper(mapper)
@@ -721,7 +723,7 @@ class Session(object):
self._validate_persistent(obj)
if self.query(obj.__class__)._get(obj._instance_key, reload=True) is None:
- raise exceptions.InvalidRequestError("Could not refresh instance '%s'" % repr(obj))
+ raise exceptions.InvalidRequestError("Could not refresh instance '%s'" % mapperutil.instance_str(obj))
def expire(self, obj):
"""Mark the given object as expired.
@@ -753,7 +755,7 @@ class Session(object):
def exp():
if self.query(obj.__class__)._get(obj._instance_key, reload=True) is None:
- raise exceptions.InvalidRequestError("Could not refresh instance '%s'" % repr(obj))
+ raise exceptions.InvalidRequestError("Could not refresh instance '%s'" % mapperutil.instance_str(obj))
attribute_manager.trigger_history(obj, exp)
@@ -954,10 +956,7 @@ class Session(object):
def _save_impl(self, obj, **kwargs):
if hasattr(obj, '_instance_key'):
- if obj._instance_key not in self.identity_map:
- raise exceptions.InvalidRequestError("Instance '%s' is a detached instance "
- "or is already persistent in a "
- "different Session" % repr(obj))
+ raise exceptions.InvalidRequestError("Instance '%s' is already persistent" % mapperutil.instance_str(obj))
else:
# TODO: consolidate the steps here
attribute_manager.manage(obj)
@@ -969,7 +968,7 @@ class Session(object):
if self._is_attached(obj) and obj not in self.deleted:
return
if not hasattr(obj, '_instance_key'):
- raise exceptions.InvalidRequestError("Instance '%s' is not persisted" % repr(obj))
+ raise exceptions.InvalidRequestError("Instance '%s' is not persisted" % mapperutil.instance_str(obj))
self._attach(obj)
def _register_persistent(self, obj):
@@ -983,7 +982,7 @@ class Session(object):
if old_id is not None and old_id in _sessions:
raise exceptions.InvalidRequestError("Object '%s' is already attached "
"to session '%s' (this is '%s')" %
- (repr(obj), old_id, id(self)))
+ (mapperutil.instance_str(obj), old_id, id(self)))
# auto-removal from the old session is disabled. but if we decide to
# turn it back on, do it as below: gingerly since _sessions is a WeakValueDict
@@ -1001,7 +1000,7 @@ class Session(object):
def _unattach(self, obj):
if not self._is_attached(obj):
- raise exceptions.InvalidRequestError("Instance '%s' not attached to this Session" % repr(obj))
+ raise exceptions.InvalidRequestError("Instance '%s' not attached to this Session" % mapperutil.instance_str(obj))
del obj._sa_session_id
def _validate_persistent(self, obj):
diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py
index 7a443b331..43f0d46d9 100644
--- a/lib/sqlalchemy/orm/unitofwork.py
+++ b/lib/sqlalchemy/orm/unitofwork.py
@@ -304,6 +304,17 @@ class UOWTransaction(object):
task.append(obj, listonly, isdelete=isdelete, **kwargs)
+ def set_row_switch(self, obj):
+ """mark a deleted object as a 'row switch'.
+
+ this indicates that an INSERT statement elsewhere corresponds to this DELETE;
+ the INSERT is converted to an UPDATE and the DELETE does not occur.
+ """
+ mapper = object_mapper(obj)
+ task = self.get_task_by_mapper(mapper)
+ taskelement = task._objects[obj]
+ taskelement.isdelete = "rowswitch"
+
def unregister_object(self, obj):
"""remove an object from its parent UOWTask.
@@ -902,7 +913,7 @@ class UOWTaskElement(object):
self.childtasks = []
self.__isdelete = False
self.__preprocessed = {}
-
+
def _get_listonly(self):
return self.__listonly