]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Add much more detail to the "unhashable types" change
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 4 Apr 2017 17:09:55 +0000 (13:09 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 4 Apr 2017 17:10:29 +0000 (13:10 -0400)
Change-Id: I34cbf54913b81ef2ae8b2e60f03feb78601460e5
Fixes: 3958
(cherry picked from commit 10a3004f2ca29921c844f58689a5f02ed5f10e03)

doc/build/changelog/migration_11.rst

index 58ca270274d709593f4a2d15e62745c8aa57f864..b3f8cb1055cea952d3dc674d5972804de05e4499 100644 (file)
@@ -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