Hibernate: не удалось лениво инициализировать коллекцию роли, сеанс или сеанс не были закрыты
Мой код:
@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 ОШИБКА: org.hibernate.LazyInitializationException не удалось лениво инициализировать сбор ролей: xxx.entity.core.User.roleSet, no сессия или сессия были закрыты org.hibernate.LazyInitializationException: не удалось лениво инициализировать сбор ролей: xxx.entity.core.User.roleSet, no сессия или сессия были закрыты org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380) в org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372) в org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365) в org.hibernate.collection.PersistentSet.add(PersistentSet.java:212) в sg.com.junglemedia.test.dao.impl.hibernate.UserDaoTest.testAddRoleAndAddUser(UserDaoTest.java:40) в sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Метод) при sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) в sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) в java.lang.reflect.Method.invoke(Method.java:597) в org.junit.runners.model.FrameworkMethod $1.runReflectiveCall(FrameworkMethod.java:44) в org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) в org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) в org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) в org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) в org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76) в org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) в org.junit.runners.ParentRunner $3.run(ParentRunner.java:193) в org.junit.runners.ParentRunner $1.schedule(ParentRunner.java:52) в org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) в org.junit.runners.ParentRunner.access $000 (ParentRunner.java:42) в org.junit.runners.ParentRunner $2.evaluate(ParentRunner.java:184) в org.junit.runners.ParentRunner.run(ParentRunner.java:236) в org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) в org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) в org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) в org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) в org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) в org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Кто-нибудь может помочь?
Ответы
Ответ 1
В классе сущности, когда вы объявляете сопоставление от пользователя к ролям, попробуйте указать fetchType для EAGER. Что-то вроде этого:
@OneToMany(fetch=FetchType.EAGER)
public Collection<Role> getRoleSet(){
...
}
UPDATE:
Последние комментарии, полученные этим ответом, заставляют меня пересмотреть это. Прошло некоторое время с тех пор, как я ответил, когда только начал работать с Hibernate. То, что Рафаэль и Мукус считают разумными. Если у вас большая коллекция, вы не должны использовать целеустремленный выбор. Он совместно выбирает все данные, сопоставленные с вашей записью, и загружает их в память. Альтернативой этому является по-прежнему использовать ленивую выборку и открывать сеанс Hibernate каждый раз, когда вам нужно работать с соответствующей коллекцией, т.е. Каждый раз, когда вам нужно вызвать метод getRoleSet. Таким образом, Hibernate будет выполнять запрос выбора к базе данных каждый раз при вызове этого метода и не сохраняет данные коллекции в памяти. Вы можете сослаться на мой пост здесь для деталей: http://khuevu.github.io/2013/01/20/understand-hibernate.html
Тем не менее, это может зависеть от вашего фактического использования. Если данные вашей коллекции невелики, и вам часто приходится запрашивать данные, вам лучше использовать целевую выборку. Я думаю, что в вашем конкретном случае коллекция роли, вероятно, довольно мала и подходит для использования с нетерпением.
Ответ 2
Вы можете попытаться добавить аннотацию @Transactional к вашему bean или методу (если объявление всех мест переменных в методе).
Ответ 3
Скорее всего, вы закрываете сессию внутри RoleDao. Если вы закроете сеанс, попробуйте получить доступ к полю на объекте, который был ленив, вы получите это исключение. Вероятно, вы должны открыть и закрыть сеанс/транзакцию в своем тесте.
Ответ 4
Следующий код может вызвать аналогичную ошибку:
using (var session = SessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
movie = session.Get<Movie>(movieId);
tx.Commit();
}
Assert.That(movie.Actors.Count == 1);
Вы можете исправить это просто:
using (var session = SessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
movie = session.Get<Movie>(movieId);
Assert.That(movie.Actors.Count == 1);
tx.Commit();
}
Ответ 5
Я столкнулся с той же проблемой, поэтому просто добавил аннотацию @Transactional, из которой я вызывал метод DAO. Это просто работает. Я думаю, что проблема в Hibernate не позволяет извлекать под-объекты из базы данных, если только не все необходимые объекты во время вызова.
Ответ 6
для меня он работал подходом, который я использовал в eclipselink. Просто вызовите размер() коллекции, который должен быть загружен, прежде чем использовать его как параметр для страниц.
for (Entity e : entityListKeeper.getEntityList()) {
e.getListLazyLoadedEntity().size();
}
Здесь entityListKeeper имеет список Entity, который имеет список LazyLoadedEntity.
Если у вас есть только то, что у Entity есть список LazyLoadedEntity, то решение:
getListLazyLoadedEntity().size();
Ответ 7
Ваша попытка загрузить ленивую загруженную коллекцию, но сеанс спящего режима закрыт или недоступен.
лучшее решение этой проблемы, измените ленивый загруженный объект на загрузку fetch = FetchType.EAGER. эта проблема будет решена.
Ответ 8
У вас есть выбор, чтобы справиться с этим. Кажется, что он возвращает нас к старым добрым SQL-дням:)
Прочтите это: http://www.javacodegeeks.com/2012/07/four-solutions-to-lazyinitializationexc_05.html
Ответ 9
У меня была эта проблема, особенно когда сущности были разбиты Jaxb + Jax-rs. Я использовал стратегию предварительной выборки, но я также нашел эффективным создание двух объектов:
- Полномасштабный объект со всеми коллекциями, отображаемый как
EAGER
- Упрощенный объект с большинством или всеми коллекциями, обрезанный
Общие поля и отображаться в @MappedSuperclass
и расширены обеими реализациями.
Конечно, если вам всегда нужны загруженные коллекции, тогда нет причин не загружать их EAGER
. В моем случае я хотел, чтобы урезанная версия объекта отображалась в сетке.
Ответ 10
В моем случае Исключение произошло, потому что я удалил
"hibernate.enable_lazy_load_no_trans = true" в файле "hibernate.properties"...
Я сделал копию и вставлю опечатку...
Ответ 11
Отметьте этот пост в блоге на испанском, который вы можете перевести. Он также имеет некоторые ссылки на другую документацию.