From: Mike Bayer Date: Tue, 4 Apr 2017 17:09:55 +0000 (-0400) Subject: Add much more detail to the "unhashable types" change X-Git-Tag: rel_1_1_9~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=10a3004f2ca29921c844f58689a5f02ed5f10e03;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Add much more detail to the "unhashable types" change Change-Id: I34cbf54913b81ef2ae8b2e60f03feb78601460e5 Fixes: 3958 --- diff --git a/doc/build/changelog/migration_11.rst b/doc/build/changelog/migration_11.rst index 58ca270274..b3f8cb1055 100644 --- a/doc/build/changelog/migration_11.rst +++ b/doc/build/changelog/migration_11.rst @@ -170,8 +170,8 @@ can instead be:: .. _change_3499: -Changes regarding "unhashable" types ------------------------------------- +Changes regarding "unhashable" types, impacts deduping of ORM rows +------------------------------------------------------------------ The :class:`.Query` object has a well-known behavior of "deduping" returned rows that contain at least one ORM-mapped entity (e.g., a @@ -198,6 +198,39 @@ The "unhashable" flag is also set on the :class:`.NullType` type, as :class:`.NullType` is used to refer to any expression of unknown type. +Since :class:`.NullType` is applied to most +usages of :attr:`.func`, as :attr:`.func` doesn't actually know anything +about the function names given in most cases, **using func() will +often disable row deduping unless explicit typing is applied**. +The following examples illustrate ``func.substr()`` applied to a string +expression, and ``func.date()`` applied to a datetime expression; both +examples will return duplicate rows due to the joined eager load unless +explicit typing is applied:: + + result = session.query( + func.substr(A.some_thing, 0, 4), A + ).options(joinedload(A.bs)).all() + + users = session.query( + func.date( + User.date_created, 'start of month' + ).label('month'), + User, + ).options(joinedload(User.orders)).all() + +The above examples, in order to retain deduping, should be specified as:: + + result = session.query( + func.substr(A.some_thing, 0, 4, type_=String), A + ).options(joinedload(A.bs)).all() + + users = session.query( + func.date( + User.date_created, 'start of month', type_=DateTime + ).label('month'), + User, + ).options(joinedload(User.orders)).all() + Additionally, the treatment of a so-called "unhashable" type is slightly different than its been in previous releases; internally we are using the ``id()`` function to get a "hash value" from these structures, just