Спящий режим не может инициализировать прокси - нет сеанса

Мой код извлекает всю информацию, связанную с пользователем:

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() просто возвращает набор Addresses пользователя.

Мой вопрос: почему объект ud все еще имеет свое значение (например, имя), хотя сеанс уже закрыт? getAddresses() — это переменная экземпляра класса UserDetails. Но почему я не могу получить его значение, но могу получить обычные переменные экземпляра класса UserDetails?

ud.getAddresses() is an @EmbeddedCollection.


person KyelJmD    schedule 21.11.2012    source источник
comment
@EmbeddedCollection — вы имеете в виду @ElementCollection?   -  person Karl Richter    schedule 02.06.2017


Ответы (3)


userAddress = ud.getAddresses();
session.getTransaction().commit();
for(Address addr: userAddress) {

Документация по спящему режиму для работы с ленивыми Associations явно называет такой доступ ошибкой. Вы можете взаимодействовать с лениво связанными объектами, только пока сеанс еще открыт. Эта часть документации также предоставляет альтернативы для доступа к таким лениво связанным членам объекта, и мы предпочитаем указывать режим выборки как JOIN в используемых критериях в наших приложениях.

person Vikdor    schedule 21.11.2012
comment
Итак, судя по всему, он на самом деле запрашивает базу данных, когда я вызываю ud.getAddresses()? - person KyelJmD; 21.11.2012

Я столкнулся с той же проблемой в 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());
}

Мой ответ запоздал, но надеюсь помочь кому-то другому :)

person doannx    schedule 03.08.2016

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

person Stanislav Bashkyrtsev    schedule 21.11.2012
comment
как насчет другого класса? считается ли это ленивой инициализацией? - person KyelJmD; 21.11.2012
comment
Да, если речь идет о МТО. И возможно, если дело дойдет до OTO. - person Stanislav Bashkyrtsev; 21.11.2012
comment
Могу ли я в любом случае использовать другие объекты внутри ud, даже если сеанс закрыт, скажем, у меня есть отношение «один ко многим»? - person KyelJmD; 21.11.2012
comment
Несколько вариантов: 1. Сразу загрузить ассоциации 2. Открыть другую сессию и прикрепить объект обратно на merge() или saveOrUpdate() 3. Не закрывать сессию (это очень сложно) - person Stanislav Bashkyrtsev; 21.11.2012
comment
как вы загружаете ассоциации? - person KyelJmD; 21.11.2012
comment
Использование fetch=join или объединение в HQL. Или используя lazy=false. - person Stanislav Bashkyrtsev; 21.11.2012