Wednesday 13 July 2011

Error Solution: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role; no session or session was closed

The problem is when I run the test, it failed on the last assert with the “org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role; no session or session was closed” error.

My DAO method and its test is as follows:


DAOImpl:
public List getActivityUIFields(ActivityType activityType) {
List rv = null;
try {
Query query = em.createNamedQuery("mobileWallet.uiConfigDAO.getUIConfigData");
query.setParameter("activityType", activityType.getValue());
rv = query.getResultList();
} catch (NoResultException nre) {
// No record found.
}
return rv;
}

DAOImplTest:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/dao-test.xml" })
@Transactional
public class UIConfigDAOImplTest {
@Autowired
private EntityManagerFactory entityManagerFactory;

private EntityManager em;

@Autowired
private UIConfigDAO uiConfigDAO;

@Before
public void setUp() {
em = entityManagerFactory.createEntityManager();
}

@After
public void tearDown() throws Exception {
}

@Test
public void testGetUIConfigData() {

List list = uiConfigDAO.getActivityUIFields(ActivityType
.getInstance("SELF"));
Assert.assertNotNull(list);
Assert.assertFalse(list.isEmpty());
Assert.assertEquals("FirstName", list.iterator().next().getValue());
Assert.assertNotNull(list.iterator().next().toString());
}
}


Its bit surprising that Assert.assertEquals("FirstName", list.iterator().next().getValue()); got passed but test failed on the next line.

Reason: Once the Hibernate Session is closed anything that hasn't been loaded, can't be loaded without reattaching your entity to a Hibernate Session. The Session will end once the statement has been executed. If I debug the test method, list has all the values and it works if getValue() is called. But fails on accessing the collection.

Solution: The whole test should be running into a transaction. The easiest way is adding @Transactional at class level. This will put the whole test method in one transaction.

We faced the similar situation when business service was called and the reason was the business service was not under one transaction. The method should be in a transaction where the retrieved collection is used. Always keep the business service in a transaction.

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. http://blog.gmorales.net/2012/03/how-to-solve-orghibernatelazyinitializa.html

    ReplyDelete
  3. @Transactional I have applied on service level still It is not worked.

    ReplyDelete