My application has been using detached entities, application-generated-IDs (GUIDs), and overridden equals/hashCode
as espoused in this article with good success.
I've been revisiting our design because we have a need for DB-generated IDs, so I reviewed
this forum post post, wherein a Hibernate team member
strongly asserts that extended sessions are preferred to assure equals/hashCode correctness.
Say I redesign my webapp with extended sessions + Hibernate-generated IDs. User posts a form, mapped to domain. Controller invokes an @Transactional service operation. Service throws validation exception => rollback tx. Session is invalidated.
Application state is now corrupt. Can't merge() because IDs and versions have been updated by flush()[1]. Impractical to find() and refresh complex application state from scratch because user changes are lost, and besides, equals/hashCode aren't reliable once the objects are detached. And around we go.[2]
My question only pertains to equals/hashCode to the extent that an extended persistence context is one "solution". Rather, I really want to know
are extended sessions still so strongly recommended? Forget other reasons to use detached objects (stateless EJBs, multi-tier distributed architectures)...what am I missing that extended sessions seem totally impractical even for basic webapps (simple architecture, but non-trivial UI), if I want to have (encapsulated + composable[3] + transactional) service operations and robust error recovery? The
Hibernate wiki says nothing more helpful than "you're on your own". Well, on my own I've tried to think through all the exception scenarios and it seems intractable.[4]
On the other hand, detached entities create some performance problems and limit lazy loading but otherwise are very easy to deal with. Copy-on-merge even has the nice property that we have not only transactional persistence, but transactional UI as well! Service operations can make all kinds of entity updates that can be thrown away right along with the transaction. Implementing a "cancel" button is trivial even in modal dialogs since we just throw away the copy. So given the difficulty of exception recovery, and the other advantages of detached entities…if my ID assignment, equals and hashCode have to be a little less pure, then so what? Why would anyone choose extended sessions, and how does one add rollback recovery in practice, for non-trivial applications?
[1] MANUAL flush mode is not enough...after all we have to flush before the final commit(), which can result in a rollback too, especially (but not exclusively) if we want to perform JSR 303 validation on commit
[2] currently, we just discard the merged copies of the entities, since we started with detached objects anyway. If the commit is successful, we can reliably use equals/hashCode to update entity references in the session.
[3] one solution is to add 100% reliable validation "up front" and simply avoid rollbacks. Aside from breaking service layer encapsulation, well...good luck :) Unfortunately I get the sense that this is the solution often used in practice, especially after reviewing Seam's demo apps.
[4] http://www.aestheticsoftware.com/archit ... ontext.htm is the most complete review of the topic I could find. Several oplock- and validation-exception recovery methods are proposed that are all incomplete and/or extremely complex and tightly coupled to the native Hibernate (non-JPA) API.