Подтвердить что ты не робот

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)

Кто-нибудь может помочь?

4b9b3361

Ответ 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. эта проблема будет решена.

Ответ 9

У меня была эта проблема, особенно когда сущности были разбиты Jaxb + Jax-rs. Я использовал стратегию предварительной выборки, но я также нашел эффективным создание двух объектов:

  • Полномасштабный объект со всеми коллекциями, отображаемый как EAGER
  • Упрощенный объект с большинством или всеми коллекциями, обрезанный

Общие поля и отображаться в @MappedSuperclass и расширены обеими реализациями.

Конечно, если вам всегда нужны загруженные коллекции, тогда нет причин не загружать их EAGER. В моем случае я хотел, чтобы урезанная версия объекта отображалась в сетке.

Ответ 10

В моем случае Исключение произошло, потому что я удалил "hibernate.enable_lazy_load_no_trans = true" в файле "hibernate.properties"...

Я сделал копию и вставлю опечатку...

Ответ 11

Отметьте этот пост в блоге на испанском, который вы можете перевести. Он также имеет некоторые ссылки на другую документацию.