29

My code:

    @Test
public void testAddRoleAndAddUser() {

    Role r = roleDao.findByProperty("name", "admin");
    if(r == null) {
        r = new Role();
        r.setName("admin");
        r.setDescription("Just administrator.");
        roleDao.save(r);
    }

    User u = dao.get(1l);
    Set<Role> roles = u.getRoleSet();
    logger.debug("Roles is null: " + (roles == null));
    roles.add(r);
    dao.save(u);
}

13:39:41,041 ERROR: org.hibernate.LazyInitializationException failed to lazily initialize a collection of role: xxx.entity.core.User.roleSet, no session or session was closed org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: xxx.entity.core.User.roleSet, no session or session was closed at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380) at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372) at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365) at org.hibernate.collection.PersistentSet.add(PersistentSet.java:212) at sg.com.junglemedia.test.dao.impl.hibernate.UserDaoTest.testAddRoleAndAddUser(UserDaoTest.java:40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Anyone help?

Visruth
  • 3,430
  • 35
  • 48
Ben
  • 1,657
  • 4
  • 16
  • 21

11 Answers11

33

In your entity class, when you declare mapping from user to roles, try specifying the fetchType to EAGER. Some thing like this:

@OneToMany(fetch=FetchType.EAGER)
public Collection<Role> getRoleSet(){
 ...
}

UPDATE: Recent comments this answer's received make me revisit this. It's been a while since I answered, when I only started working with Hibernate. What Rafael and Mukus say are reasonable. If you have a large collection, you shouldn't use eager fetching. It jointly selects all data mapped to your entry and loads to memory. An alternative to this is to still use lazy fetching and open a Hibernate session each time you need to work on the related collection, i.e, each time you need to invoke getRoleSet method. This way, Hibernate will execute the select query to database each time this method is invoked and doesn't keep the collection data in memory. You can refer to my post here for details: http://khuevu.github.io/2013/01/20/understand-hibernate.html

That's said, it can depend on your actual use case. If your collection data is small and you frequently need to query the data, you will better off using eager fetching. I think, in your specific case, a collection of role is probably quite small and suitable to use eager fetching.

Khue Vu
  • 3,112
  • 4
  • 37
  • 40
  • I faced a similar problem by mapping collections with many to many(and the fetch type is not specified). I got LazyInitializationException but when I changed to fetch type Eager it was working properly. Is is anything wrong in fetch type Lazy? – vvekselva Aug 24 '12 at 08:52
  • 1
    @vvekselva, you can refer to this question: http://stackoverflow.com/questions/2990799/difference-between-fetchtype-lazy-and-eager-in-java-persistence – Khue Vu Aug 26 '12 at 01:46
  • 4
    @Rafael +1. This just cannot be a solution. Not when the parent has more than one OneToMany or if any of them returns quite a lot of rows. Why would anyone want to return data from other tables when you only need data from one parent. This is a bad bad bad solution. The only time I would want to use EAGER is if it is the inverse of this and that only means one row (provided this does not eagerly load something else which loads something else). – Mukus Apr 12 '14 at 03:56
  • 1
    The github post is gone. =( – Fodder Nov 11 '14 at 05:17
  • 1
    Hi @Fodder, the valid link is here: http://khuevu.github.io/2013/01/20/understand-hibernate.html Let me know if u have feedback – Khue Vu Nov 14 '14 at 17:22
  • so what's the downside of using eager? performance lost? anyway, eager can solve my issue for the moment? – frogcdcn Jun 26 '15 at 08:05
  • @frogcdcn, the downside is that if you load all relational data to memory, you will run out of memory. But if the relation is small enough to fit in memory, it will give u better performance. – Khue Vu Aug 10 '15 at 11:24
  • Github link is 404 :-( – Necromancer Aug 25 '17 at 13:14
  • 1
    @KhueVu please update your github link!! is it this one? https://khuevu.github.io/application-design-with-hibernate.html – Pipo Sep 13 '18 at 09:38
20

You can try to add @Transactional annotation to your bean or method (if declaration of all variables places in method).

DraggonZ
  • 1,057
  • 1
  • 16
  • 22
  • Ran into this exact error and realized that I needed a @Transactional annotation (for my Spring test context) as mentioned here. – 8bitme Oct 13 '14 at 12:12
  • You can do it within your production code of course, but you should avoid to make your test methods transactional. Otherwise you would not be able to test the correct transactionhandling of your productioncode – Mariano Nov 19 '18 at 14:38
5

You're most likely closing the session inside of the RoleDao. If you close the session then try to access a field on an object that was lazy-loaded, you will get this exception. You should probably open and close the session/transaction in your test.

Javid Jamae
  • 8,741
  • 4
  • 47
  • 62
  • This is the case for me. During data deletion, I have to copy out the data I need from the entity model object first, then delete the entity model object, before finally use the copied data for other things. – tom_mai78101 Sep 28 '21 at 20:14
4

I was experiencing the same issue so just added the @Transactional annotation from where I was calling the DAO method. It just works. I think the problem was Hibernate doesn't allow to retrieve sub-objects from the database unless specifically all the required objects at the time of calling.

Athar
  • 579
  • 5
  • 12
3

for me it worked the approach that I used in eclipselink as well. Just call the size() of the collection that should be loaded before using it as parameter to pages.

for (Entity e : entityListKeeper.getEntityList()) {
    e.getListLazyLoadedEntity().size();
}

Here entityListKeeper has List of Entity that has list of LazyLoadedEntity. If you have just therelation Entity has list of LazyLoadedEntity then the solution is:

getListLazyLoadedEntity().size();
makkasi
  • 6,328
  • 4
  • 45
  • 60
3

The following code can cause similar error:

  using (var session = SessionFactory.OpenSession())
  using (var tx = session.BeginTransaction())
  {
      movie = session.Get<Movie>(movieId);
      tx.Commit();
  }
  Assert.That(movie.Actors.Count == 1);

You can fix it simply:

  using (var session = SessionFactory.OpenSession())
  using (var tx = session.BeginTransaction())
  {
      movie = session.Get<Movie>(movieId);
      Assert.That(movie.Actors.Count == 1);
      tx.Commit();
  }
jiang peng
  • 41
  • 2
3

In my case the Exception occurred because I had removed the "hibernate.enable_lazy_load_no_trans=true" in the "hibernate.properties" file...

I had made a copy and paste typo...

Laura Liparulo
  • 2,849
  • 26
  • 27
2

You have different choices to handle this. It seem like its taking us back to old good plain SQL days :)

Read this: http://www.javacodegeeks.com/2012/07/four-solutions-to-lazyinitializationexc_05.html

bkomac
  • 1,140
  • 10
  • 9
2

I've had this issue especially when entities are mashalled by Jaxb + Jax-rs. I've used the pre-fetch strategy, but I have also found it effective to provide two entities:

  1. Full-blown entity with all collections mapped as EAGER
  2. Simplified entity with most or all collections trimmed out

Common fields and be mapped in @MappedSuperclass and extended by both entity implementations.

Certainly if you always need the collections loaded, then there is no reason to not to EAGER load them. In my case I wanted a stripped down version of the entity to display in a grid.

Kalle Richter
  • 8,008
  • 26
  • 77
  • 177
Jason Holmberg
  • 291
  • 2
  • 17
0

The best way to resolve this issue is to use a try-catch block in the Service layer around the area where there is an error while fetching the property and then just reload the entity:

IBaseEntityDAO<IYourEntity> dao = ApplicationConfig.getDAOFactory().getDAO(IYourEntity.class);

dao.refresh(yourentityvariable);
Procrastinator
  • 2,526
  • 30
  • 27
  • 36
-1

Your trying to load the lazy loaded collection, but the hibernate session is closed or unavailable. the best solution for this problem, change the lazy loaded object to eager fetch = FetchType.EAGER loading. this problem will solve.

priya
  • 23
  • 1