On Dec 10, 2007, at 3:07 PM, Adam Batkin wrote:

> Can you suggest other alternatives for the above use case? Having to
> call flush before doing anything that might require the ID seems
> excessive and too low-level for code like that.
>
> I know for a fact that Hibernate does it this way (not that sqlalchemy
> has to do everything Hibernate does), and I can't imagine a use case
> where doing what's needed to retrieve database-generated fields on an
> as-needed basis would be considered incorrect behavior.
>

ive never seen that one before,  i.e. the id generator being called in  
direct reaction to calling myentity.getId().  In our hibernate apps we  
often check for the id being null in order to check if the entity is  
persisted yet.  if you only mean that hibernate generates its own IDs  
externally to INSERTs, yes thats true.  SQLAlchemy would not use that  
method by default since most of our users want to use their databases  
native ID generation utilities,  which on sqlite, mysql and others  
only occur during INSERT, but we have no issue with providing that  
method of id generation as an option if people want it (and of course  
we have the hooks for user-defined default generation functions).

So, im assuming the desired feature here (before getting into your  
furher comments below) is, upon access to a primary key attribute, get  
the id, *without* issuing an INSERT or a flush, and assign it to the  
attribute.  Thats pretty easy to do provided you dont mind using a non- 
native id generation method on certain databases.

So, first to get the id, either:

        1. use a sequence, dont use mysql or sqlite
        2. use an external id generation function.  if youd like to provide  
ones that work with databases like mysql and sqlite, and they are  
atomic/threadsafe/all that good stuff,  we can add them as features.   
i dont get into those myself because of the various issues with  
atomcity but ive no issue with using one that is properly constructed.

So if either ID generation function of #1 or #2 is available, they can  
easily be installed on a mapped class.  Theres three ways this can be  
done, and the first two you can play with without us modifying  
SQLAlchemy at all.

1. just build a class property which checks for none, calls the id  
generator and applies.    0.4.2 has an easier syntax for setting up  
"synonyms" which allow you to decorate the behavior of a class  
attribute, but you can do this with any version of SA (just that it  
works better in 0.4.2).
2. I can show you the less-than-public API we use to put "value  
generation" callables on attributes, i.e. the same one that issues  
deferred loads and lazy relation loads.  this would be a little more  
like the start of an actual feature.
3. building on #2 would be some feature to SA called "eager-fetch-ids"  
or something like that, which looks at the Column for a  
DefaultGenerator that is executable (Sequences, for example, are  
executable DefaultGenerator objects).  it would probably just take a  
list of keys and apply to any columns you want, not just pk cols.

I dont consider the above behavior, or lack of it, to be "correct" or  
"incorrect".  i think most of our users would be surprised by it and  
would prefer to leave it off, but if some people prefer it thats fine  
by me.

now the next comment, much deeper can of worms:

> "As far as the application is concerned, objects in the Pending and
> Persistent states should function identically."

OK, above we are talking just about primary key generation...its not  
that big a deal.   But here, the difference between pending and  
persistent is huge.  If your proposal is, "pending acts just like  
persistent, without flushing", i would ask how you'd approach these  
examples:

        x = Foo()
        print x.id   # generates id, prints 1
        enhedgine.execute("select * from table where id=" + x.id)

above, the query is directly to the DB.

Another example, which we actually support right now...but its because  
a flush occurs:

        x = Foo()
        x.id = 7
        for a in x.addresses:   # lazy load of "where x=7".

> (it's possible that this feature would be difficult to implement, in
> which case that's a good answer and maybe it can go on to a far-off
> wishlist, or I can try to implement it or something, I just don't  
> see a
> way for it to be considered incorrect behavior)

like i said none of this is "incorrect", but if you are getting at the  
idea that we'd start querying for things within the session that  
havent been flushed, i.e. effectively building our own "select" engine  
in python, that would get really hairy.  we will eventually implement  
some invalidation of persistent objects based on criterion, but thats  
about it, and that can still issue SQL if it needs to since it only  
acts on persistent instances.



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to