我们假设我有这个课程:
@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实例值与即将被保存(更新)到数据库的新值.我这样做与preupdate 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();
所以这会触发mylistener中的preUpdate方法,当我尝试:
MyClass.findById(someLongId);
当我调试我已经得到新更新的实例,但更新还没有发生,因为当我检查数据库列姓仍然是Dylan.
解决方法
我认为一个简单的方法是将以前的值保存在暂时变量中,JPA不会持久存在.
所以只需要介绍一个变量prevIoUsSurname并保存实际值,然后再在setter中覆盖它.
所以只需要介绍一个变量prevIoUsSurname并保存实际值,然后再在setter中覆盖它.
如果要保存多个属性,如果您的类MyClass是Serializable,那将很容易.
如果这样添加一个post load监听器
public class MyClass implements Serializable { @Transient private transient MyClass savedState; @PostLoad private void saveState(){ this.savedState = SerializationUtils.clone(this); // from apache commons-lang } }
但请注意,savedState是一个分离的实例.
然后,您可以访问EntityListener中的上一个状态.
您也可以将PostLoad侦听器移动到EntityListener类.但是,您需要访问savedState字段.我建议将其作为范围限制或使用一个封装范围的访问器,并将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; } }