02 March 2010

Hibernate : "failed to lazily initialize a collection", Reasons and Solutions

Al Salamo Alykom

Most of us usually focuses the most famous hibernate problem "failed to lazily initialize a collection", So here I'll try to say Why it appears and How to solve.

First Why it appears, When you map a one-to-many relation ship, the default load mode is lazy loading, and this is the best choice thing because Hibernate will not gonna load a collection of objects in memory until you use them.
So, If you try to access this collection within the same session you get the parent object, it will works fine.

So the problem happens when you try to access a collection of some object outside the initiating session.

Second, How to solve.
Hibernates uses proxies to refer to collections (and objects as well) when returned as reference to another object.
Suppose we have tow objects, Country and Region, each Region can contain many countries, So the following code will return an exception:

......
session.beginTransaction();
Region region = (Region) session.get(Region.class, 1);
session.getTransaction().commit();
session.close();
printCountryList(region.getCountries()); // << The problem will happen here

So, Should I keep the session opened across client requests, or what should I do?

There are two solutions and I tried both and both works for me.
Hibernate team says that whevener you accessed any method on the proxy, we will load the (real) object (collection ) for you.
So, In case of the previous example, all you have to do is to call any method on the collection within the session, say size():

......
session.beginTransaction();
Region region = (Region) session.get(Region.class, 1);
region.getCountries().size(); // will make hibernate initialize the collection for you instead of the proxy
session.getTransaction().commit();
session.close();
printCountryList(region.getCountries()); // << Will works very fine

Or you can use Hibernate.initialize() to initialize the collection from the proxy :

session.beginTransaction();
Region region = (Region) session.get(Region.class, 1);
Hibernate.initialize(region.getCountries()); // will make hibernate initialize the collection for you instead of the proxy
session.getTransaction().commit();
session.close();
printCountryList(region.getCountries()); // << Will works very fine


That's all, please if you have such the problem, try any of these ways and tell me know about your feedback.
Thanks.

6 comments:

Anonymous said...

Great example - thanks a bunch !

Anonymous said...

the region.getCountries().size(); tips works like a charm, thanks a lot!

RAVI SHANKER said...

hibernate.intialize is the better option

sadame said...

Hi there, I would like to know how different this is to lazy="false" because to me, initializing the collection before closing the session by either the NHibernate method of the .size() tip, is the same as initializing everything since the beginning.

Anonymous said...

Thank you,

Yair

Israel

Anonymous said...

Thanks a lot!
From many days I lost my mind with this problem...
Hibernate.initialize it works very very well and you make me very happy :)
Thanks Thanks Thanks

Fabio.