获取对象字段以前的值休眠JPA

2022-01-13 00:00:00 annotations caching java Hibernate 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 实例与即将保存(更新)到数据库的新值.我使用更新前方法来做到这一点:

Now in my MyListener class I'm trying to figure out the previous value MyClass instance versus the new value that is about to get saved(updated) to database. I do this with preupdate metdhod :

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

所以假设我有一个带有姓名和姓氏的 MyClass 对象实例:

So assuming I have a MyClass objects instance with name and surname :

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

这没有被听众接收到,这没关系,因为我只收听更新.现在,如果我要像这样更新这个实例:

This wasn't picked up by listener which is ok because I'm listening only to updates. Now if I were to update this instance like so :

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

所以这会触发 mylistener 中的 preUpdate 方法,当我尝试时:

So this triggers the preUpdate method in mylistener and when I try to :

MyClass.findById(someLongId);

当我调试时,我已经获得了新更新的实例,但更新尚未发生,因为当我在 surname 列中检入数据库时​​,它仍然是 Dylan.

When I debug I already get the newly updated instance but the update hasn't happened yet because when I check in database in column surname it's still Dylan.

如何在我的 preUpdate 方法中而不是我刚刚更新的方法中从数据库中获取值?

How do I get the value from database in my preUpdate method and not the one I just updated?

推荐答案

我认为一种简单的方法是将先前的值保存在 JPA 不会持久的瞬态变量中.因此,只需引入一个变量 previousSurname 并保存实际值,然后再将其覆盖在 setter 中.

I think an easy way is to save the previous value in a transient variable that JPA will not persist. So just introduce a variable previousSurname and save the actual value before you overwrite it in the setter.

如果你想保存多个属性,如果你的类 MyClassSerializable.

If you want to save multiple properties it would be easy if your class MyClass is Serializable.

如果是这样,添加一个后加载监听器

If so add a post load listener

public class MyClass implements Serializable {

     @Transient
     private transient MyClass savedState;

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

}

但请注意,savedState 是一个分离的实例.

But be aware that the savedState is a detached instance.

然后您可以在 EntityListener 中访问之前的状态.

You can then access the previous state in your EntityListener.

您还可以将 PostLoad 侦听器移动到 EntityListener 类.但是您需要访问 savedState 字段.我建议将其设置为包作用域或使用包作用域访问器并将 MyClassMyListener 放在同一个包中,

You can also move the PostLoad listener to the EntityListener class. But then you need access to the savedState field. I recommend to make it either package scoped or use a package scoped accessor and put MyClass and MyListener in the same package,

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;
     }

}

相关文章