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

Все примитивные свойства классов загружаются сразу, они не могут быть ленивыми, если вы не используете улучшения байт-кода. Только настоящие ассоциации, подобные вашей коллекции, могут лениться.