Hibernate не может инициализировать прокси - нет сеанса
Мой код извлекает всю информацию, связанную с пользователем:
SessionFactory sessionFactory = HibernateUtilities.configureSessionFactory();
Session session = sessionFactory.openSession();
UserDetails ud = null;
Set<Address> userAddress = null;
try {
session.beginTransaction();
ud = (UserDetails) session.get(UserDetails.class, 1);
userAddress = ud.getAddresses();
session.getTransaction().commit();
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
session.close();
}
System.out.println(ud.getName());
for(Address addr: userAddress){
System.out.println("State " + addr.getState());
}
ud.getAddresses()
просто возвращает набор Address
es пользователя.
Мой вопрос: почему объект ud
все еще имеет свое значение (например, имя), хотя сеанс уже закрыт? getAddresses()
- это переменная экземпляра класса UserDetails
. Но почему я не могу получить его значение, но я могу получить обычные переменные экземпляра класса UserDetails
?
ud.getAddresses()
является @EmbeddedCollection
.
Ответы
Ответ 1
userAddress = ud.getAddresses();
session.getTransaction().commit();
for(Address addr: userAddress) {
Документация hibernate для работающая с ленивыми ассоциациями, явно вызывает такой вид доступа как ошибку. Вы можете взаимодействовать с лениво связанными объектами только в то время, когда сеанс все еще открыт. Эта часть документации также предоставляет альтернативы для доступа к таким лениво связанным элементам объекта, и мы предпочитаем указывать режим выборки как JOIN в используемых критериях в наших приложениях.
Ответ 2
Я столкнулся с той же проблемой в JPA/Hibernate, и есть два способа решить эту проблему:
1/Отключите LAZY по умолчанию, как показано ниже:
@Entity
@Proxy(lazy = false)
public class Project {
...
}
Конечно, этот способ не рекомендуется из-за проблемы с производительностью, поэтому вы можете перейти ко второму пути.
2/Вы можете поместить @Transactional в начале вашего метода, он может помочь вам оставаться сессией или другим пониманием, он передает сессию в Hibernate следующим образом:
@Test
@Transactional
public void testSaveGroup() {
Department g = new Department();
g.setName("XDG");
assertNull(g.getId());
this.groupRepo.save(g);
assertNotNull(g.getId());
System.out.println(g.getId());
Project dummyPrj = new Project(123L, "KSTA", new Date(), "NEW", "Helm AG", g);
this.projectRepo.save(dummyPrj);
// verify
List<Department> lst = this.groupRepo.findAll();
Project savedPrj = this.projectRepo.getOne(123L);
Assert.assertEquals("XDG", savedPrj.getGroup().getName());
}
Мой ответ задерживается, но надеюсь помочь кому-то другому:)
Ответ 3
Все примитивные свойства классов загружаются сразу, они не могут быть ленивыми, если вы не используете улучшения байт-кода. Только настоящие ассоциации, подобные вашей коллекции, могут лениться.