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.
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.
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:Perhaps you can try the Formatter solution described in this blog.
If you are wondering (like me) why Formatters instead of Converters, I found this paragraph in spring docs useful:
consider the type conversion requirements of a typical client environment such as a web or desktop application. In such environments, you typically convert from String to support the client postback process, as well as back to String to support the view rendering process. In addition, you often need to localize String values. The more general core.convert Converter SPI does not address such formatting requirements directly. To directly address them, Spring 3 introduces a convenient Formatter SPI that provides a simple and robust alternative to PropertyEditors for client environments.
In general, use the Converter SPI when you need to implement general-purpose type conversion logic; for example, for converting between a java.util.Date and and java.lang.Long. Use the Formatter SPI when you’re working in a client environment, such as a web application, and need to parse and print localized field values. The ConversionService provides a unified type conversion API for both SPIs.
(Off topic: Is it just me or is Spring documentation one of the most confusing works of software documentation out there?! It confuses me far more often than it clarifies!)
Roel De Nijs wrote:I have never used the possibility of generating the database script using the ORM. I always manually create the necessary DDL (and DML) scripts and execute them manually. My JPA entities don't have any annotation required to generate the database script (besides the column names of course
)
Ben Souther wrote:Got it.
Google is my friend.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4513568
The answer for anyone else reading this is to call getErrorStream if the response code is not 200.