Reputation: 1667
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?
Upvotes: 29
Views: 156427
Reputation: 49
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);
Upvotes: 0
Reputation: 2897
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...
Upvotes: 3
Reputation: 291
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:
EAGER
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.
Upvotes: 2
Reputation: 7288
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();
Upvotes: 3
Reputation: 3152
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.
Upvotes: 33
Reputation: 629
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.
Upvotes: 5
Reputation: 1087
You can try to add @Transactional annotation to your bean or method (if declaration of all variables places in method).
Upvotes: 20
Reputation: 1200
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
Upvotes: 2
Reputation: 23
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.
Upvotes: -1
Reputation: 41
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();
}
Upvotes: 3
Reputation: 9009
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.
Upvotes: 5