From: Mike Bayer Date: Tue, 15 Jun 2010 18:04:13 +0000 (-0400) Subject: - Can now call make_transient() on an instance that X-Git-Tag: rel_0_6_2~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=27b9b3578ddf421f990cd7a2ab7c9635178b210b;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Can now call make_transient() on an instance that is referenced by parent objects via many-to-one, without the parent's foreign key value getting temporarily set to None - this was a function of the "detect primary key switch" flush handler. It now ignores objects that are no longer in the "persistent" state, and the parent's foreign key identifier is left unaffected. --- diff --git a/CHANGES b/CHANGES index 53c90278ba..a479afa9a6 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,15 @@ CHANGES - Subquery-eager-loading now works with Query objects which include params(), as well as get() Queries. + + - Can now call make_transient() on an instance that + is referenced by parent objects via many-to-one, + without the parent's foreign key value getting + temporarily set to None - this was a function + of the "detect primary key switch" flush handler. + It now ignores objects that are no longer + in the "persistent" state, and the parent's + foreign key identifier is left unaffected. - sql - The warning emitted by the Unicode and String types diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py index ba2ae8889c..7a8c4cf702 100644 --- a/lib/sqlalchemy/orm/dependency.py +++ b/lib/sqlalchemy/orm/dependency.py @@ -776,7 +776,7 @@ class DetectKeySwitch(DependencyProcessor): uowcommit, self.passive_updates) def _pks_changed(self, uowcommit, state): - return sync.source_modified(uowcommit, + return state.has_identity and sync.source_modified(uowcommit, state, self.mapper, self.prop.synchronize_pairs) diff --git a/test/orm/test_naturalpks.py b/test/orm/test_naturalpks.py index a352e3b34d..b89456fda2 100644 --- a/test/orm/test_naturalpks.py +++ b/test/orm/test_naturalpks.py @@ -2,14 +2,15 @@ Primary key changing capabilities and passive/non-passive cascading updates. """ -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from sqlalchemy.test.testing import eq_, ne_, assert_raises, assert_raises_message import sqlalchemy as sa from sqlalchemy.test import testing from sqlalchemy import Integer, String, ForeignKey, Unicode from sqlalchemy.test.schema import Table, Column from sqlalchemy.orm import mapper, relationship, create_session, backref +from sqlalchemy.orm.session import make_transient from sqlalchemy.test.testing import eq_ -from test.orm import _base +from test.orm import _base, _fixtures class NaturalPKTest(_base.MappedTest): @@ -149,11 +150,15 @@ class NaturalPKTest(_base.MappedTest): def go(): sess.flush() if not passive_updates: - self.assert_sql_count(testing.db, go, 4) # test passive_updates=False; load addresses, update user, update 2 addresses + self.assert_sql_count(testing.db, go, 4) # test passive_updates=False; + #load addresses, update user, update 2 addresses else: self.assert_sql_count(testing.db, go, 1) # test passive_updates=True; update user sess.expunge_all() - assert User(username='jack', addresses=[Address(username='jack'), Address(username='jack')]) == sess.query(User).get('jack') + assert User(username='jack', addresses=[ + Address(username='jack'), + Address(username='jack')]) == \ + sess.query(User).get('jack') u1 = sess.query(User).get('jack') u1.addresses = [] @@ -363,6 +368,38 @@ class NaturalPKTest(_base.MappedTest): r = sess.query(Item).with_parent(u2).all() eq_(Item(itemname='item2'), r[0]) +class TransientExceptionTesst(_fixtures.FixtureTest): + run_inserts = None + + @testing.resolve_artifact_names + def test_transient_exception(self): + """An object that goes from a pk value to transient/pending + doesn't count as a "pk" switch. + + """ + mapper(User, users) + mapper(Address, addresses, properties={'user':relationship(User)}) + + sess = create_session() + u1 = User(id=5, name='u1') + ad1 = Address(email_address='e1', user=u1) + sess.add_all([u1, ad1]) + sess.flush() + + make_transient(u1) + u1.id = None + u1.username='u2' + sess.add(u1) + sess.flush() + + eq_(ad1.user_id, 5) + + sess.expire_all() + eq_(ad1.user_id, 5) + ne_(u1.id, 5) + ne_(u1.id, None) + eq_(sess.query(User).count(), 2) + class ReversePKsTest(_base.MappedTest): """reverse the primary keys of two entities and ensure bookkeeping succeeds."""