Получение поля объекта предыдущее значение спящий JPA

Предположим, что у меня есть этот класс:

@EntityListeners({MyListener.class})
class MyClass {
  String name;
  String surname;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name; 
  }

  public String getSurname() {
    return name;
  }

  public void setSurname(String name) {
    this.name = name; 
  }

  public void save() {
    JPA.em().persist(this);
    return this;
  }

  public void update() {
    JPA.em().merge(this);
  }

  public static MyClass findById(Long id) {
    return JPA.em().find(MyClass.class, id);
  }
}

Теперь в моем классе MyListener я пытаюсь вычислить предыдущий экземпляр MyClass сравнению с новым значением, которое собирается получить (обновлено) в базе данных. Я делаю это с предварительным metdhod:

@PreUpdate
public void preUpdate(Object entity) {
...some logic here...unable to get the old object value in here           
}

Поэтому, предполагая, что у меня есть экземпляр объектов MyClass с именем и фамилией:

MyClass mycls = new MyClass();
mycls.setName("Bob");
mycls.setSurname("Dylan");
mycls.save();

Это не было воспринято слушателем, что нормально, потому что я слушаю только обновления. Теперь, если бы я обновил этот экземпляр так:

MyClass cls = MyClass.findById(someLongId)
cls.setSurname("Marley");
cls.update();

Таким образом, это вызывает метод preUpdate в mylistener и когда я пытаюсь:

MyClass.findById(someLongId);

Когда я отлаживаю, я уже получаю обновленный экземпляр, но обновление еще не произошло, потому что когда я проверяю базу данных в фамилии столбца, это все еще Dylan.

Как получить значение из базы данных в моем методе preUpdate а не в том, что я только что обновил?

Ответ 1

Я думаю, что простой способ - сохранить предыдущее значение в переходной переменной, которая JPA не будет сохраняться. Поэтому просто введите переменную previousSurname и сохраните фактическое значение, прежде чем перезаписывать его в сеттере.

Если вы хотите сохранить несколько свойств, было бы легко, если бы ваш класс MyClass был Serializable.

Если это так, добавьте прослушиватель после загрузки

public class MyClass implements Serializable {

     @Transient
     private transient MyClass savedState;

     @PostLoad
     private void saveState(){
        this.savedState = SerializationUtils.clone(this); // from apache commons-lang
     }

}

Но имейте в savedState что savedState является отдельным экземпляром.

Затем вы можете получить доступ к предыдущему состоянию в своем EntityListener.

Вы также можете переместить PostLoad слушателя к EntityListener класса. Но тогда вам нужно получить доступ к поля savedState. Я рекомендую сделать его либо с областью MyListener пакета, либо с помощью пакета с расширенным MyListener и поместить MyClass и MyListener в тот же пакет,

public class MyListener {

    @PostLoad
    private void saveState(MyClass myClass){
         myClass.saveState(SerializationUtils.clone(myClass)); // from apache commons-lang
    }

}

public class MyClass implements Serializable {

     @Transient
     private transient MyClass savedState;

     void saveState(MyClass savedState){
        this.savedState = savedState;
     }

}