Karthik Shiraly wrote:
Can you elaborate where exactly you are facing this problem? Some code would be helpful.
While I agree lazy init exceptions are a nuisance, I'm not able to think of a scenario where it makes iteration impossible.
Since they occur when hibernate proxies are accessed outside hibernate sessions, they are indicators that something may be lacking in your design.
As I see it, it's the same optimization that we'd do manually when using regular SQL JDBC queries, that is, don't fetch data which is not needed right now.
Karthik Shiraly wrote:The technique I always use to overcome this is the "open session in view" servlet filter. It's a well described solution on the net; just search for it.
It's a servlet filter that opens a hibernate session as soon as request is received, stores it in thread local variable and retains the session until the reponse goes out via same filter.
Just add it to your web.xml.
Hibernate sessions will now remain alive for the lifetime of the entire request-to-response chain, including JSP/other view rendering, rather than lifetime of just the DAO method.
It's not the neatest of solutions because a DAO layer concept is leaking into higher layers, but then hibernate has always been slammed for its leaky abstractions and this is yet another one.
On the plus side, it does keep the OR model clean (without it, one would have to do all the link table trickery you've mentioned), while also optimizing SQL fetching and caching.
Tim Holloway wrote:Open Session in View is indeed a horrible thing. Because the session is open for the duration of the request/response cycle, you can accidentally zap data in the database, to say nothing of potential performance and security problems.
What I do is to work with a 2-tier persistence architecture. Within those 2 tiers, you have full persistence connectivity. Outside those tiers, you are disconnected (detached). The boundary between the persistence tiers and the higher app tiers (business logic) is also the transaction extent.
The upper persistence tier is the "service" layer. The methods in that layer are all transactional. That is, when you invoke one of those methods, you begin a database transaction and when you exit the method, the transaction is committed (or rolled back, in case of failure).
The lower persistence tier is the DAO layer. A DAO class handles the CRUD and Find functions for a single database table. Or in some cases, a parent/child table. The DAOs inherit their transaction context from the service tier methods that invoke them.
The reason for having 2 tiers is to allow my basic table operations to remain simple. They're all done in the DAOs. The service methods, on the other hand, handle complex table interrelationships. For example, if I have an A class that relates to a Y class with children of class Z, the service method can do a fetch of a selected A with its associated Y and Zs. This is returned as a detached graph of entities. The application code can then display and/or modify this graph. If it modifies the graph, then there's typically a "save" method in the service tier that then takes that updated graph and invokes the DAO methods for the objects in that graph to cause it all to get posted to the database.
In some cases I'll have more than one service-tier fetch method. It will typically be named something like "findXXXWithYYYY" or "findXXXWithChildren". That allows me to define a simple lazy-fetch find to get basic info, and a deep-fetch find when I need details.
The deep-fetch find will either manually reference the secondary objects to force-load them (since it's dealing with connected objects) or in cases where the ORM system supports "fetch sets", it may invoke a fetch set that includes the items that in the default fetch are lazy-load.