Hibernate OneToOne сопоставленный объект устанавливает все свойства в null

Использование Hibernate 5, Spring 4

Пожалуйста, рассмотрите ниже коды и сопоставление между двумя объектами:

Класс пользователя

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private TruckOwner truckOwner;

//сеттеры-получатели ниже

Класс TruckOwner

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

//getter setter ниже

Когда мой код пытается обновить значения внутри класса user, как показано ниже: Класс UserServiceImpl

@Override
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void resetPassword(Long userId,String newPassword) {

    User user = userDAO.findById(userId);

    user.setPassword(newPassword);
    System.out.println(user.getTruckOwner().getTruckOwnerId());     
    userDAO.merge(user);
}

При вызове userDAO.merge(user); появляется ошибка ниже: не-переходный объект имеет нулевой идентификатор: com.mymodel.TruckOwner

Я сталкиваюсь с такой проблемой во многих местах моего проекта, пожалуйста, помогите мне с правильным решением этой проблемы и почему класс TruckOwner имеет все значения null, заданные с помощью hibernate?

Ответ 1

Нам нужно знать реализацию метода userdao merge, но я предполагаю, что он называется merge методом hibernate Session interface В любом случае объект, не являющийся переходным, является объектом TruckOwner; hibernat не будет извлекать объект, когда вы вызываете System.out.println(user.getTruckOwner().getTruckOwnerId());, кроме того, в этом пункте вы выходите из сеанса спящего режима, и если вы вызываете другого получателя грузовика, кроме getTruckOwnerId(), вы должны получить org.hibernate.LazyInitializationException (или подобное. t правильно запомнить)

Я думаю, у вас есть 2 варианта:

  • как было предложено staszko032, вы должны изменить тип выборки на EAGER
  • Когда вы загружаете пользовательский объект с помощью userDAO.findById(userId);, вы должны fetch объект truckOwner внутри сеанса hibernate, вызывая любой другой метод внутри реализации userDAO.findById(userId); и внутри сеанса hibernate

Я надеюсь, что это полезно

Анжело

Ответ 2

Попробуйте это для класса грузовика:

@Entity
@Table(name = "truckOwner")
public class TruckOwner{
...
private User user;


@OneToOne(fetch = FetchType.LAZY, mappedBy = "truckOwner", cascade = CascadeType.ALL)
public User getUser() {
    return this.user;
}
}

И это для класса User:

@Entity
@Table(name = "user")
public class User{
     private TruckOwner truckOwner;


    @OneToOne(fetch = FetchType.LAZY)
    @PrimaryKeyJoinColumn
     public TruckOwner getTruckOwner() {
          return this.truckOwner ;
     }

}

Ответ 3

Режим ожидания не является решением, если вы создаете производственное приложение. Проблема в вашей сессии уже закрыта, когда вы пытаетесь getTruckOwner. Попробуйте передать сеанс всем методам resetPassword.

Ответ 4

Сначала вы не должны использовать merge здесь! Вы почти никогда не должны использовать слияние.

Слияние должно использоваться, когда у вас есть неуправляемый объект (сериализованный или загруженный предыдущим контекстом постоянства) и хотите объединить его в текущий контекст сохранения, чтобы сделать его управляемым объектом. Ваша организация уже управляется, поскольку контекст персистентности был загружен вашим DAO внутри транзакции, управляемой контейнером. Это означает, что вам не нужно даже требовать сохранения, любые изменения в управляемом объекте будут обнаружены и сохранены при совершении транзакции.

На поверхности JPA выглядит просто, потому что большая часть сложности не видна на поверхности, бог знает, что я ударил головой о стену, когда я начал с TopLink 7 лет назад, но после прочтения Жизненные циклы объектов и контекст постоянства контейнера, управляемый контейнером, я сделал намного больше ошибок, и было гораздо проще расшифровать сообщения об ошибках.

Ответ 5

Другим решением будет изменение типа выборки в режиме EAGER в классе User. В режиме LAZY спящий режим не загружает TruckOwner, подключенный к пользователю, поскольку он явно не нужен в вашем случае. В конечном итоге TruckOwner имеет значение null для пользователя, но имеет значение nullable = false, и поэтому слияние происходит с ошибкой.