--- /dev/null
+.. change::
+ :tags: bug, orm
+ :tickets: 4647
+
+ A warning is now emitted for the case where a transient object is being
+ merged into the session with :meth:`.Session.merge` when that object is
+ already transient in the :class:`.Session`. This warns for the case where
+ the object would normally be double-inserted.
+
key = state.key
if key is None:
+ if state in self._new:
+ util.warn(
+ "Instance %s is already pending in this Session yet is "
+ "being merged again; this is probably not what you want "
+ "to do" % state_str(state)
+ )
+
if not load:
raise sa_exc.InvalidRequestError(
"merge() with load=False option does not support "
from sqlalchemy.orm.interfaces import MapperOption
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import eq_
+from sqlalchemy.testing import expect_warnings
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import in_
from sqlalchemy.testing import not_in_
self.assert_sql_count(testing.db, go, 0)
+ def test_warn_transient_already_pending_nopk(self):
+ User, users = self.classes.User, self.tables.users
+
+ mapper(User, users)
+ sess = create_session()
+ u = User(name="fred")
+
+ sess.add(u)
+
+ with expect_warnings(
+ "Instance <User.*> is already pending in this Session yet is "
+ "being merged again; this is probably not what you want to do"
+ ):
+ u2 = sess.merge(u)
+
+ def test_warn_transient_already_pending_pk(self):
+ User, users = self.classes.User, self.tables.users
+
+ mapper(User, users)
+ sess = create_session()
+ u = User(id=1, name="fred")
+
+ sess.add(u)
+
+ with expect_warnings(
+ "Instance <User.*> is already pending in this Session yet is "
+ "being merged again; this is probably not what you want to do"
+ ):
+ u2 = sess.merge(u)
+
def test_transient_to_pending_collection(self):
User, Address, addresses, users = (
self.classes.User,