dmiller wrote: > On Feb 12, 2006, at 4:48 PM, Michael Bayer wrote: >> Well, I was pursuing this differently. While I am moving in the >> same direction where UnitOfWork is not really dealt with >> publically, I have the Session's main purpose as managing the >> "scope" of a set of unit of works, such as thread-local, per- >> application, or custom. > > May I respectfully disagree...I don't think the session should be > managing scope. The session is the object that should be managed in a > given "scope". If you really want to make the session manage the > scope, then it should be a singleton (which is basically what the > original objectstore was--a module, not a class). Otherwise we're > talking about nested scopes, which gets very complicated to > understand (and hard to debug). I don't think that is as useful as > keeping it simple with a single UnitOfWork per session by default > (well, not quite since the begin/commit thing will create additional > "units of work").
fine with me....I knew pretty well when I did the original implementation, which was just a single thread-local storage for a bunch of UnitOfWorks, that the scoping issue was going to come up since that design was intentionally simplistic....it wasnt occurring to me how else it might want to be used so i didnt pursue. The way i did it right now has the disadvantage that theres a lot of thread-local lookups in a row for no clear reason. Also, that you tried to get your app to specify window IDs and at the end of the day it was unworkable in practice makes a lot of sense to me, so back to being simple is great. Using inheritance as the primary means to extend the Session slightly raises my gang-of-four sense (i.e. http://www.c2.com/cgi/wiki?CompositionInsteadOfInheritance ) but its not that big a deal to me, since I dont think people are going to need this very much at all...plus Python encourages inheritance of standard objects all over the place. >> and have foo()'s transaction pulled upwards to the outermost >> transaction. you need a begin/commit counter to do that. > > Hmm. Is there a test for that? I don't think my patch is causing it > to fail. no theres no test for that as of yet....but its a pattern Ive used in lots of other places. it just means session.begin()/commit() will need a counter inside of it to keep track of the outermost begin()/commit() pair. for a similar idea see the docs for threading.RLock (http://www.python.org/doc/2.3.4/lib/rlock-objects.html) where they call it a "recursion counter". Previously, I had it so that new unitofwork objects just get compounded on top of each other so that you could have "nested transactions", but it became clear that wasnt the usual use case....but its easy enough to make both behaviors available via an option on the session. so to sum up: a thread-local ScopedRegistry gets placed at the module level in objectstore, and stores a bunch of Session objects, one for each thread. Each Session contains one UnitOfWork and delgates operations to it. UnitOfWork is constructed with no awareness of the Session, and contains just a commit method. UnitOfWork can also take an IdentityMap as an argument which allows related UnitOfWork objects to be constructed. Session implements begin/commit and maintains a stack of UnitOfWork objects for this purpose. It may work in "recursion counter" mode or possibly "nested transaction" mode. Session also gets it own register_new()/register_clean() methods which take incoming objects and calls bind_to with them, before delgating onto the UOW, thus binding those instances to this Session. objectstore implements get_session() which returns the current thread-local Session object, or given an object instance returns the Session that was bound to this object, if any, or just the thread-local session otherwise. the outside world is given get_session() as the primary method of getting a unit of work context, and nobody really deals with the UnitOfWork class directly. objectstore/mapper also provide ways to specify a different Session for the scope of a particular operation, by placing the new Session in the ScopedRegistry for this thread, then popping it off after the operation is complete. mapper provides the "using()" method, objectstore provides push_session/pop_session. Objects that are created or loaded within such a block get "bound to" that Session, so that subsequent operations involving those instances will call up that Session object. an object can also be explitly created as bound to a Session anywhere by specifying the keyword argument "_sa_session" to its constructor. If the Session to which an object is bound falls out of scope, it gets garbage collected and operations upon those objects will raise an exception. calling operations like session.clear() will cause Session to remove its internal UnitOfWork instance and replace with a new one. objects that were bound to this session remain bound to it. so let me know if this works for you...hopefully I can get this change in tonight or tomorrow. I am going to try really hard, once this change is in place, to put out a release, just so that the trunk can handle more changes coming down without throwing off everyone already using the library in projects, since people are starting to grumble about that. I was hoping to release already but this will have to be fixed up first. - mike ------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Do you grep through log files for problems? Stop! Download the new AJAX search engine that makes searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! http://sel.as-us.falkag.net/sel?cmd=lnk&kid=103432&bid=230486&dat=121642 _______________________________________________ Sqlalchemy-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users

