2

I have many questions to ask about hibernate sessions, because I'm having continuous issues with them.

I'm using Spring 3.1.1 and Hibernate 4.1.3.

first here is the class diagram that I'm working on.

class diagram

code classes:

public class Equipement {

  @ManyToOne(fetch = FetchType.LAZY)
  @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
  public getOffice(){
    return office ;
  }

public class Office {    
  @ManyToOne(fetch = FetchType.LAZY)
  @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
  public getService(){
    return service ;
  }

public class Service {
  @ManyToOne(fetch = FetchType.LAZY)
  @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
  public getDepartement(){
    return departement ;
  }

Here is how I load all my equipement.

public class HibernateEquipementDao{

  @SuppressWarnings("unchecked")
  public List<Equipement> getAll() {
      return sessionFactory.getCurrentSession().createQuery("from Equipement").list() ;
  }
}

Suppose I load all my equipements in a List<Equipement> allEquipements and want for example to populate my view with only equipements of some service or some departements.

 List<Equipement> aListOfEquipements = new ArrayList<Equipement>() ;
 for(Equipement equipement : allEquipements)
   if(equipement.getOffice().getService().getName().equals("name"))
     aListOfEquipements.add(equipement) ;

Can I really do this whenever I want ? the session called Current is always active ? sometimes I get that exception. org.hibernate.LazyInitializationException: could not initialize proxy - no Session

that makes me ask where is the Current session that my EquipementDao use ?

Is there a way to open a session when I want to get the Departement of an Equipement ?

Or there is another way to proceed ? how manage sessions and how to load all my Equipements and access the other entities with no problems ?

elaich
  • 939
  • 1
  • 19
  • 35

3 Answers3

3

Add layer for services, I know this name is not so lucky in your case, but in this layer you will have classes responsible for your logic.

Some prototype:

public class EquipmentService {

   @Inject
   private HibernateEquipementDao dao;

   @Transactional
   public List<Equipement> doSomethingWithEquipmentWithoutLazyException(Equipment equipment){
      List<Equipement> allEquipments = dao.getAll();

      List<Equipement> aListOfEquipements = new ArrayList<Equipement>() ;
      for(Equipement equipement : allEquipements) {
         if(equipement.getOffice().getService().getName().equals("name")) {
             aListOfEquipements.add(equipement) ;
         }
      }
      return aListOfEquipments;
   }

}

Very imporatan is annotation: @Transactional it means that session will be open at the begining and close at the end of method, so there is no way to throw a LazyLoadingException.

Some interesting thread about Transactonal: Where does the @Transactional annotation belong?

Community
  • 1
  • 1
chris
  • 669
  • 9
  • 16
  • that annotation is just magic and awesome, so whenever i have a method doing some transactional actions in my service layer, i better put that annotation first. – elaich Sep 24 '12 at 12:46
  • The LazyLoadingException is back, and now it's because SpEL expression `${equipement.office.name}` in my jsp... – elaich Sep 24 '12 at 17:40
  • After finish method with @Transactional annotation, session is closed. So if you are not initialize "office" then you will got LazyLoadingExsception. Run your application in debug, and you will see. – chris Sep 25 '12 at 06:59
3

i have see two ways to solve this problem.

1. Open session in view:

You can configure your hibernate setting open session in view. If you are configuring your hibernate programatically, you can use this line:

jpaProperties.put(org.hibernate.cfg.Environment.ENABLE_LAZY_LOAD_NO_TRANS, true)

Other way is declare a filter in web.xml like this:

    <filter>
        <filter-name>OpenEntityManagerInViewFilter</filter-name>
        <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>OpenEntityManagerInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

This aproach will afect all your system and can be bad to your performance.

2. FETCH JOIN:

You can use FETCH JOIN in your query to force hibernate to load data, for example:

from Equipement e FETCH JOIN e.office

This aproach will be more hard to do (many points afected in your system) and be careful.

3. Call get method after query return:

In your DAO you can call the get methods after the query return. I don´t like this way, but normally work.

Wel, i wish that i helped you.

  • DO NOT USE THIS FEATURE. It is broken and you will loose your data. https://hibernate.atlassian.net/browse/HHH-7971 – Vojtěch Mar 17 '14 at 14:03
0

For most Web applications it is simplest and absolutely appropriate to have the current transaction span the whole request. The simplest approach is to have a Filter that starts the the transaction and commits/rolls back at the end of the request. In Spring/Hibernate this is called Open Entity in View pattern. Spring offers a filter implementation via org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter for that.

When using this approach, the view, i.e. your JSPs, participate in the same transaction and do not need to reload and can navigate entities also in case of fetchtype LAZY relations.

gnomie
  • 439
  • 5
  • 16
  • I have solved this problem using another approach, i found that i can also use an **Interceptor** so i used this: `` – elaich Sep 26 '12 at 12:30
  • Great. And sorry that I was not very precise. If you are not JPA bound you may be using the Hibernate specific version, i.e. based on the Hibernate session rather than the entity manager. That interceptor AFAICT makes sure the transaction is spanning from request start to end in contrast to just controller (vs. view) operations as implemented by the approach in the (marked as) answer. – gnomie Oct 05 '12 at 10:08