On Mar 8, 2012, at 4:45 PM, zz elle wrote: > Hi everyone, > > I join an application dev team in order to solve 2 main problems with SA on > an application that use SA the wrong way. > > > Indeed the dev team did not understood that sessions are "ad-hoc" (as said by > Mike if i remember well). > So they get DetachedInstanceError sometimes on lazy loads. > First some detached errors were solved using joinedload(_all) in SA queries. > Secondly they discover that scoped_session solve every errors, indeed > scoped_session provide session alive for the life of a thread so SA objects > never get detached from their session ... > Except when you get an SA object with some query in a thread T1, start an > asynchronous thread T2 with the object as argument and T1 ends (so T1 session > will be destroyed by python gc) ... > And you get new detached errors.
when you transfer an object to a new thread, you do this: def im_receiving_an_object_from_another_thread(obj): obj = my_threads_session.merge(obj) that is, use merge() to transfer the state of the object to the session that's local to the thread. > > The application i am currently speaking is about more >100k code lines, so i > can not change the way the application use SA. > Is there an elegant way to catch silently DetachedInstanceError and merge the > associated object to an alive session ? OK, guess you knew about merge(). erm, might be tricky. merge() returns a new object in the first place, as the given object might still be related to the session from the other thread, and you'd get some nasty concurrency-related issues. So even if there were some event that could link to that new session, the calling code would need to get a hold of the newly merged object as the thing it should be dealing with. I'd maybe give a second look to actually fixing the code, unfortunately. Whenever you see objects being passed to another thread would be where you want to do the merge. You can even make a decorator that does it, like : @merge_objects("a", "b", "c") def run_some_code(a, b, c): @merge_objects() is given the string names of the arguments it should be merging, pulls them from the argument list (probably using inspect() to reconcile the names in merge_objects() with how they should be received/passed to the function) and passes merged versions to the function. > > One elegant way i think of to solve the problem would be to wrap SA object > into a higher level object which handles session troubles (detached case, > thread/scope session). that would be very involved. The object graph is a nasty beast. > Currently i implement some PoC by overloading the query_cls but i was only > able to proxify SA objects "directly" returned by the query. > I mean in the following query User SA object would be wrapped but not SA > objects listed in user.roles. > session.query(User).option(joinedload(User.roles)).all() > Is it the good class to overload ? > Is it better to overload lazyloader (if it's possible) ? OK maybe overriding query() you could trick it into using the "correct" session, still, its quite sloppy that the calling code would be dealing with a mix of objects pointing to two different sessions. A more explicit approach like the decorator might lead to clearer results in the end. Or maybe not. You'd need to experiment quite a bit. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.