From: Mike Bayer Date: Fri, 17 Apr 2015 21:03:16 +0000 (-0400) Subject: - add documentation describing the behavioral change in relationship X-Git-Tag: rel_1_0_1~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bd61e7a3287079cf742f4df698bfe3628c090522;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - add documentation describing the behavioral change in relationship assignments that we would see from #3060; fixes #3369 --- diff --git a/doc/build/changelog/migration_10.rst b/doc/build/changelog/migration_10.rst index 462b6361d0..da00f1c633 100644 --- a/doc/build/changelog/migration_10.rst +++ b/doc/build/changelog/migration_10.rst @@ -8,7 +8,7 @@ What's New in SQLAlchemy 1.0? undergoing maintenance releases as of May, 2014, and SQLAlchemy version 1.0, released in April, 2015. - Document last updated: March 17, 2015 + Document last updated: April 17, 2015 Introduction ============ @@ -1014,7 +1014,8 @@ INSERT statement in relational databases considers a missing value to be the same as NULL in most cases. Whether SQLAlchemy received a history event for a particular attribute set to None or not would usually not matter; as the difference between sending None/NULL or not wouldn't have an impact. -However, as :ticket:`3060` illustrates, there are some seldom edge cases +However, as :ticket:`3060` (described here in :ref:`migration_3060`) +illustrates, there are some seldom edge cases where we do in fact want to positively have ``None`` set. Also, allowing the attribute event here means it's now possible to create "default value" functions for ORM mapped attributes. @@ -1032,6 +1033,58 @@ symbol, and no change to the object's state occurs. :ticket:`3061` +.. _migration_3060: + +Priority of attribute changes on relationship-bound attributes vs. FK-bound may appear to change +------------------------------------------------------------------------------------------------ + +As a side effect of :ticket:`3060`, setting a relationship-bound attribute to ``None`` +is now a tracked history event which refers to the intention of persisting +``None`` to that attribute. As it has always been the case that setting a +relationship-bound attribute will trump direct assignment to the foreign key +attributes, a change in behavior can be seen here when assigning None. +Given a mapping:: + + class A(Base): + __tablename__ = 'table_a' + + id = Column(Integer, primary_key=True) + + class B(Base): + __tablename__ = 'table_b' + + id = Column(Integer, primary_key=True) + a_id = Column(ForeignKey('table_a.id')) + a = relationship(A) + +In 1.0, the relationship-bound attribute takes precedence over the FK-bound +attribute in all cases, whether or not +the value we assign is a reference to an ``A`` object or is ``None``. +In 0.9, the behavior is inconsistent and +only takes effect if a value is assigned; the None is not considered:: + + a1 = A(id=1) + a2 = A(id=2) + session.add_all([a1, a2]) + session.flush() + + b1 = B() + b1.a = a1 # we expect a_id to be '1'; takes precedence in 0.9 and 1.0 + + b2 = B() + b2.a = None # we expect a_id to be None; takes precedence only in 1.0 + + b1.a_id = 2 + b2.a_id = 2 + + session.add_all([b1, b2]) + session.commit() + + assert b1.a is a1 # passes in both 0.9 and 1.0 + assert b2.a is None # passes in 1.0, in 0.9 it's a2 + +:ticket:`3060` + .. _bug_3139: session.expunge() will fully detach an object that's been deleted