Alok
Alok

Reputation: 244

org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed

I keep on getting this error "Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed" when I run the following code:

public ArrayList<ProfileDTO> getInitialProfiles(Contracts ct){ 
   SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
   Session session=sessionFactory.openSession();
   Transaction tx=session.beginTransaction(); 
   ArrayList<ProfileDTO> profileDTOs=new ArrayList<ProfileDTO>();
   try{
       Hibernate.initialize(ct);
        SQLQuery query=session.createSQLQuery("select {b.*},{p.*},{t.*} from bidtool.bt_boiler_plates b,bidtool.bt_profile p,bidtool.bt_trade_lane t where b.contract_id=:val AND p.contract_id=:val AND t.contract_id=:val")
                  .addEntity("b",Boiler_Plates.class)
                  .addEntity("p",BidToolProfiles.class)
                  .addEntity("t",BidToolTradeLanes.class);
        query.setParameter("val", ct.getContract_id());
        List list=query.list();  

        Iterator iteContract = list.iterator();
        while ( iteContract.hasNext() ) {
            Object[] pair =(Object[]) iteContract.next();
            Boiler_Plates bp=(Boiler_Plates)pair[0];
            BidToolProfiles p=(BidToolProfiles)pair[1];
            ProfileDTO profileDTO=new ProfileDTO();
            profileDTO.setProfileId(p.getProfileId());
            profileDTO.setBt_contracts(p.getBt_contracts());
            profileDTO.setCreated(p.getCreated());
            profileDTO.setProfileContent(p.getProfileContent());
            profileDTO.setEditable(p.getEditable());
            profileDTO.setProfileName(p.getProfileName());
            profileDTOs.add(profileDTO);
        } 
        return profileDTOs;
   }
   catch(Exception ex){
       System.out.println(ex.getMessage());
       return profileDTOs;
   }
   finally{
    session.flush();   
    session.close();
   }
 }

It works fine whenever I don't close the session but I cannot do that. I need to close the session. Your help will be appreciated. Thank you.

Upvotes: 2

Views: 18587

Answers (4)

JB Nizet
JB Nizet

Reputation: 692181

Well, you need to initialize every object that you plan to use once the session is closed.

Suppose you have a User entity with a OneToOne lazy association with its address. And suppose you load the user while the session is open. Since the address is lazy loaded, the first time you'll call a method on the address (user.getAddress().getStreet() for example), Hibernate will execute a query to load the address of the user, and thus be able to give you access to its street. But if the session is closed, there is no connection to the database anymore, the User entity is detached, and Hibernate thus throws this exception.

Use Hibernate.initialize() to initialize the objects you need, or execute a query which has the necessary fetches to load everything needed at once.

Side note: your exception handling is awful. When asked to return the profiles, instead of saying: "sorry but I couldn't do that due to the following exception", you basically ignore the exception and say "There is no profile in the database". Please imagine a cancer detection system works this way. Would you like your cancer to stay undetected because the system had an exception?

Upvotes: 3

Johanna
Johanna

Reputation: 5303

Use session.merge() to merge the instance loaded from an old session with the new session. This by the way means Hibernate loads the entity again from the database.

The other possibility is to avoid lazy loading - either in the mapping or by accessing the necessary values as long as the session is still open (even if the values are not necessary in that moment).

Upvotes: 0

Jeshurun
Jeshurun

Reputation: 23186

The error is raised when you access an association or a collection in an hibernate entity after the session has been closed. Looking at your code, I am guessing the problem probably lies in the following line:

profileDTO.setBt_contracts(p.getBt_contracts());

when you try to access this collection elsewhere in your code, from within a different Session.

Try changing your query to:

select {b.*},{p.*},{t.*} from bidtool.bt_boiler_plates b,bidtool.bt_profile p,bidtool.bt_trade_lane t left join fetch p.bt_contracts btcontracts where b.contract_id=:val AND p.contract_id=:val AND t.contract_id=:val

Notice that I have added a join fetch on the collection. This should make sure that the contracts collection is fetched at the same time the BidToolProfiles entity is fetched. Also try initializing the collection before setting it in your DTO.

Hibernate.initialize(p.getBt_contracts());
profileDTO.setBt_contracts(p.getBt_contracts());

Upvotes: 6

Yannis
Yannis

Reputation: 6157

How are you using that method? What are your mappings like? What properties do you have lazy-loading enabled? Is this a web app? You are creating a ProfileDTO but what about getBt_contracts. That will return stuff from the "Session-enabled" BidToolProfiles so if you access lazy-loaded properties after that method returns then you get this error.

This is just an example of what I think is wrong given that I cant see your mappings. The important thing here is that the session should close after you have lazy-loaded ALL the properties that you need to perform the required task.

And again - depending on whether this is a web app or not you can go for different session m management strategies (Session per Request on web apps, Session per Thread if its a desktop app etc)

Upvotes: 0

Related Questions