On Jan 10, 2014, at 8:44 AM, Paul Moore <p.f.mo...@gmail.com> wrote:

> 
> So far, so good. But if I want to create a new Release, things get messy. 
> This is my basic function:
> 
> def new_release(package, version, data):
>     r = Release(version)
>     r.package = Package(package)
>     # Populate the data in r, and create child items
>     return r
> 
> It's that package reference that messes me up. If the release is for a new 
> package, then when I merge the release into the session, the package is 
> created. But if it's for an existing package, a new package is created (which 
> gives a constraint error if the package name is unique, and duplicates if 
> it's not) rather than the session recognising that it's an existing package 
> and linking the release to it.
> 
> If I was working at the SQL core level, I'd expect to have to query for the 
> package and create it if it wasn't there. But I'm not sure I can do that with 
> a session, as things get cached in memory by the "unit of work" stuff, and I 
> don't know if a query for the release could miss a package that's pending 
> insertion, or if the query could cause auto-flushing which might cause other 
> issues (either with performance or integrity). Because the session is 
> managing the in-memory caching and the transaction management "by magic", I 
> don't want to interfere with its mechanisms any more than I have to. If I 
> have to keep track of what's gone to the database, and query for existing 
> instances and manage the transactions, I probably should just use the SQL 
> layer directly (I have a lot of experiences with databases, but very little 
> with ORMs, so pure DB code isn't too scary for me, but on the other hand I 
> don't know what benefits the ORM should be giving me that I'm not seeing).

there’s various patterns for dealing with the very common issue of “create 
unique object if not exists, else use the current one”.  One that I frequently 
point to is the unique object recipe:

http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject

uniqueobject is a generalization.   You can of course just run the specific 
query yourself.  this is not in any way interfering with the ORM mechanisms - 
the unit of work is pretty much a simple identity dictionary in this sense, 
either a key exists for a given identity or it doesn’t (but keep in mind, 
“identity” to the unit of work means, “primary key identity”.  Not any of the 
other columns that are just part of unique constraints).

As mentioned elsewhere, Session.merge() kind of does this as well, but merge() 
only does so with the primary key of the instance, not for arbitrary fields, 
and I would agree that merge() is often more trouble than it’s worth - its 
complexity is that it can cascade the merge operation along relationships, not 
often needed for simple cases.


Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to