Friday, January 25, 2008

Hibernate Collections Lazy Initialization Gotcha

I have some code that looks like this:

AdContent.java (EJB3):
@CollectionOfElements
@JoinTable(name="AdContentSites",
joinColumns={@JoinColumn(name="adContentId")})
@Enumerated(EnumType.STRING)
@Column(name="siteName", nullable=false)
@Cache(usage=CacheConcurrencyStrategy.TRANSACTIONAL)
Set siteNames;
public Set getSiteNames() { return this.siteNames; }

This creates a join table called AdContentSites which maps an AdContent object to one or more SiteName's. SiteName is an enum. I then transform AdContent into a POJO called AdContentData and make that available to the web tier.

This is the transform method:
public static AdContentData adContent(AdContent raw)
{
// Need to lazily initialize the collection
raw.getSiteNames().size();

AdContentData adc = new AdContentData(
raw.getId(),
raw.getName(),
raw.getContent(),
raw.getSiteName(),
raw.getStart(),
raw.getEnd(),
raw.getCreatedBy(),
raw.getCreated());
return adc;
}

The part that bit me in the ass for a while was the fact that Hibernate lazily populates Collections. I kept getting the less than helpful error: "failed to lazily initialize a collection of role: com.kink.heart.entity.adn.AdContent.siteNames, no session or session was closed"

The solution (as you can see above) was to force Hibernate to initialize the Collection by calling AdContent.getSiteName().size(). Maybe it is just me, but I would have expected the call further down to raw.getSiteNames() to do that work for me, but I guess because of the way the object proxy works, that isn't what is going to happen.

12 comments:

Sreenath V said...

Its still not working in my case.
I have a EJB method with TX set to NOT SUPPORTED, and inside this method i query Entity A. A has collection of Entity B which is marked as Lazy. Now with in the EJB method when I call A.getBs().size(), i get

Message : failed to lazily initialize a collection of role: com.test.A.bs, no session or session was closed
Exception Stack Trace
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.test.A.bs, no session or session was closed

Jon Scott Stevens said...

It sounds like you are having issues with the transaction session and not necessarily the same problems I was having. With regards to the transaction session, I'm not sure how I can help you without actually looking at your source code.

akkyy said...

I was getting the same exception. It went off when I removed the code to commit the transaction started.

Not sure if this would leave my transaction open and create problems further. But the lazy initialization error went off.

catalyst said...

Have a look at this: http://hibernate.org/43.html
Problem described and several workarounds suggested.

yaytul said...
This comment has been removed by the author.
yaytul said...
This comment has been removed by the author.
dirk said...

sessionFactory.getCurrentSession().update(raw);

should also do the trick. The update tells hibernate to associate the object with the session again.

Jon Scott Stevens said...

dirk, the problem isn't that the session is not associated, it is that the collection is lazily loaded.

Денис said...

@CollectionOfElements(fetch=FetchType.EAGER)

In my case it still won't work

Jon Scott Stevens said...

which is why you need to call .size()

ask said...

@Transactional

try this

sajit said...

Thank you for the very helpful post