[patch] Fix problems with database default primary keys and MappedCollections

Issue #1102 resolved
Former user created an issue

When the keyfunc includes a mapped object's primary key, it is necessary to flush to the database if that key is a calculated default (e.g. from a sequence). e.g.

ob = MyObject()
session.add(ob)
session.flush()
MyCollection.set(ob)

This patch removes the need to explicitly call session.flush()

Index: collections.py
===================================================================
--- collections.py      (revision 4906)
+++ collections.py      (working copy)
@@ -1372,6 +1372,10 @@
         """Add an item by value, consulting the keyfunc for the key."""

         key = self.keyfunc(value)
+        if key is None:
+            from sqlalchemy.orm.session import object_session
+            object_session(value).flush() # ensure the primary key exists
+            key = self.keyfunc(value)
         self.__setitem__(key, value, _sa_initiator)
     set = collection.internally_instrumented(set)
     set = collection.appender(set)

Comments (4)

  1. jek

    There are a number of problems with this patch:

    1. None is a perfectly valid key for a collection
    2. no check that keyfunc has a server-assigned PK value as a dependency, and flushes needlessly in most cases
    3. it implicitly flushes the user's session, regardless of how the session is configured

    It's pretty trivial to make your own custom mapped collection type that addresses this use case && apply it where the behavior is appropriate. I have doubts that the base classes could ever be patched to detect this use case automatically and do what you want here, but please feel free to prove me wrong. :)

  2. Mike Bayer repo owner

    it should be very trivial - literally take the four lines of code in the patch, and apply it instead within a custom "keyfunc", which can be sent as an argument to mapped_collection. Grok (this is for grok, right?) can just apply this function in the context of using their own rdb module. This works because Grok already assumes a particular session configuration that is compatible with the approach.

  3. Log in to comment