0

I have a pretty complex domain entities. I want to have lazy loading for all of associations. So the scenario is like this:

1.get an instance of my business logic.

2.get an object o from business.

3.ask o to give me other associated objects.

4.prepare the view.

To get rid of hibernate exceptions about closed session when lazy load other objects, I've come up to the idea to open and close entire session in controller. Is it a good idea? Are there any better solutions?

Thank you

arash_k
  • 3
  • 5

4 Answers4

1

Session in view is a bad practice.

Here is a suggestion for layers which are typically used to work around this problem:

Controller

  • The controller is only concerned with handling web requests, interpreting them into objects that your services will deal with, and returning services results as web responses. I usually have only one transactional service method call in each controller method, preferring to keep all data access for one controller operation within a single transaction.

Service

  • The service layer is only concerned with accepting data from controller, obtaining the data it needs (from data layer) to perform its operations, and returning meaningful results. The service should fully load all lazy-loaded entities required by the controller. The service methods here are transactional and won't have lazy loading issues, and you can assemble results from multiple DAO's. That way DAO's don't need to know about each other.

Data Access

  • The data access layer is only concerned with persistence (CRUD), allowing access to data with filtering, ordering, and so on.
Community
  • 1
  • 1
Jay
  • 6,684
  • 3
  • 36
  • 44
  • In my project, I have Controller layer, then it calls a business logic logic layer which only contains static methods. The business logic layer works with persistent entities and may return an entity to upper layers which is not completely loaded. The problem raises when that upper layer( here Controller) wants to use unloaded associations. What is your suggestion to tackle this problem? – arash_k Jul 27 '12 at 18:17
  • A more general question is that do you agree with my current architecture? – arash_k Jul 27 '12 at 18:17
  • The service should fully load all lazy-loaded entities required by the controller if it is returning entities to the controller. If the controller may or may not want to load different entities, you may want to move some of that logic into the service. For instance, using different service methods to return differently-loaded data, or adding parameters to service methods to specify what needs to be loaded. – Jay Jul 27 '12 at 19:21
  • For your general architecture, I'd say that using only static methods for you service / business logic layer will make it harder to test, but that's partly a style decision that's up to you. – Jay Jul 27 '12 at 19:23
  • Thank you, indeed, I will put some of controllers responsibilities in logic layer. – arash_k Jul 28 '12 at 05:28
  • 1
    Looking at tags I suppose you're using SpringMVC. Why don't you inject logic-layer services into controller instead of using static methods? – Piotr Gwiazda Jul 30 '12 at 10:04
  • I second that: injecting logic into your controller instead of accessing via static methods is considered best practice. – Jay Jul 30 '12 at 12:26
0

Spring has an opensessioninviewfilter and a opensessininviewinterceptor which should handle this functionality for you.

Kurt Du Bois
  • 7,112
  • 4
  • 22
  • 32
  • I couldn't find a proper example which would work for me. Do you know any working example? – arash_k Jul 27 '12 at 10:53
  • http://static.springsource.org/spring/docs/1.2.9/api/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.html and http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.html. Choosing between those 2 will be based on your use case, but in a web application the filter is preferable. – Kurt Du Bois Jul 27 '12 at 10:56
0

As a design pattern openinig session in view is very bad. I think that SpringMVC has a setting that causes opening session for you and solves your problem.

However I'd suggest not using this pattern if your application is more complex than a pet store. I'd suggest moving data retrieval and business logic one layer down and leave only UI-related code in controllers. Tethinking relations and setting eager and lazy settings on them should work. Setting everything to lazy without analysis is not a good idea. It'll end up in hundreds of SQL calls per request.

I'd suggest plugging L2 cache (e.g. EHCache) to Hibernate. Configuration and usage is really easy.

Piotr Gwiazda
  • 11,796
  • 12
  • 53
  • 87
  • So you mean I insert a new layer between controller and business logic to handle session open/close matters? – arash_k Jul 27 '12 at 10:59
  • No, I mean that transaction handling should be placed in business logic layer and view layer (i.e. controller) should not know if you read data from database via JPA, JDBC or from MongoDB, CSV or whatever data store you can imagine. Your controller should handle view logic (data validation, formatting etc.) and delegate everything else to the business layer. – Piotr Gwiazda Jul 27 '12 at 13:03
  • I have a question, what do you mean about business layer? In my project the business layer consists of two layers, first one only contains functionalities(static methods) and second one only contains entities which most of them are persistent. Now I think that I have to put transactional behavior in my first business layer. Is it a good practice to have another layer on top of these two and place transactions on them? – arash_k Jul 27 '12 at 18:24
  • Static methods!?!!?! By a business layer I mean everything that knows and processes any business logic inside your application. Commonly theese are stateless components, often called services. For service components it makes no difference if it is fired from GUI, WebService, incomming message, JMX etc. Entities are just POJOs that get persisted. No business logic in there. – Piotr Gwiazda Jul 30 '12 at 09:33
0

You can indeed do it and it is a common pattern when using Spring and Hibernate. You can enable it very easily by putting the code below in your web.xml

<filter>
    <filter-name>lazyLoadingFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>lazyLoadingFilter</filter-name>
    <url-pattern>/mvc/*</url-pattern>
</filter-mapping>

Once the you have this in place, every call in hibernate made within that call will use the same session:

@Autowired
protected SessionFactory sessionFactory;

protected Session getSession() {

    return SessionFactoryUtils.getSession(sessionFactory, true);
}

However, as Peter Gwiazda says, you may or may not want to do this depending on the scale and complexity of your application. It sounds like your objects are quite complex so having your views essentially trigger more SQL statements as you traverse your entity in your JSP or whatever is not going to lead to great performance.

It is generally a better pattern to convert your object into a DTO with just what your view needs and limit the amount of data you fetch back from your database.

Kieran
  • 5,646
  • 3
  • 22
  • 32
  • Thank you. But I have one more question; After applying the settings that you mentioned, how can I access the session in order to run hql or performing other tasks? – arash_k Jul 27 '12 at 11:25
  • Made an edit to show how you get the session. You'll always be getting the same session and the filter you added will make sure it is opened and closed at the start/end of the request. – Kieran Jul 27 '12 at 12:31
  • I downvoted because session in view is a bad practice. See http://stackoverflow.com/questions/1103363/why-is-hibernate-open-session-in-view-considered-a-bad-practice – Jay Jul 27 '12 at 17:45
  • So you also agree with the idea of placing transactions and session managements(open/close) in code and not to use filters, right? – arash_k Jul 27 '12 at 18:26
  • Little harsh to downvote because it is bad practice when I acknowledge the better pattern at the end of my answer. Oh well. – Kieran Jul 27 '12 at 21:02
  • The question was "Is it a good idea..." and this answer opens with "You can indeed do it and it is common..." which I think is the wrong answer. And the caveat at the end is mostly someone else' answer (Peter Gwiazda's). No offense, just acting on what I think are right and wrong answers. – Jay Aug 01 '12 at 14:00