summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES2
-rw-r--r--lib/sqlalchemy/orm/mapper.py5
-rw-r--r--test/orm/unitofwork.py19
3 files changed, 25 insertions, 1 deletions
diff --git a/CHANGES b/CHANGES
index 798d33fac..423a47e7c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -24,6 +24,8 @@ required for firebird, not a bad idea for others [ticket:408]
- default "timezone" setting is now False. this corresponds to Python's datetime
behavior as well as Postgres' timestamp/time types (which is the only timezone-sensitive
dialect at the moment) [ticket:414]
+- added an error message if you actually try to modify primary key values on an entity
+and then flush it.
0.3.3
- string-based FROM clauses fixed, i.e. select(..., from_obj=["sometext"])
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 67ca75bb3..b6ff09616 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -841,7 +841,10 @@ class Mapper(object):
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)
-
+ 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))
+
inserted_objects = util.Set()
updated_objects = util.Set()
diff --git a/test/orm/unitofwork.py b/test/orm/unitofwork.py
index ed3b9fca1..c1f885bb0 100644
--- a/test/orm/unitofwork.py
+++ b/test/orm/unitofwork.py
@@ -3,6 +3,7 @@ from sqlalchemy import *
import testbase
import pickleable
from sqlalchemy.orm.mapper import global_extensions
+from sqlalchemy.orm import util as ormutil
from sqlalchemy.ext.sessioncontext import SessionContext
import sqlalchemy.ext.assignmapper as assignmapper
from tables import *
@@ -403,6 +404,24 @@ class PKTest(UnitOfWorkTest):
e.data = 'some more data'
ctx.current.flush()
+ def testpksimmutable(self):
+ class Entry(object):
+ pass
+ mapper(Entry, table)
+ e = Entry()
+ e.multi_id=5
+ e.multi_rev=5
+ e.name='somename'
+ ctx.current.flush()
+ e.multi_rev=6
+ e.name = 'someothername'
+ try:
+ ctx.current.flush()
+ assert False
+ except exceptions.FlushError, fe:
+ assert str(fe) == "Can't change the identity of instance Entry@%s in session (existing identity: (%s, (5, 5), None); new identity: (%s, (5, 6), None))" % (hex(id(e)), repr(e.__class__), repr(e.__class__))
+
+
class ForeignPKTest(UnitOfWorkTest):
"""tests mapper detection of the relationship direction when parent/child tables are joined on their
primary keys"""