假设我有这个课:
@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来做到这一点:
MyListener
MyClass
@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();
因此,这会触发preUpdatemylistener中的方法以及当我尝试执行以下操作时:
preUpdate
MyClass.findById(someLongId);
当我调试时,我已经获得了新近更新的实例,但是更新尚未发生,因为当我在“姓”列中检入数据库时,它仍然是Dylan。
Dylan
如何从我的preUpdate方法而不是我刚刚更新的方法中从数据库中获取值?
我认为一种简单的方法是将先前的值保存在JPA将不会持久的瞬态变量中。因此,只需引入一个变量previousSurname并保存实际值,然后再在设置器中将其覆盖即可。
如果要保存多个属性,如果您的班级MyClass是Serializable.
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。
EntityListener
您也可以将PostLoad侦听器移至EntityListener该类。但是随后您需要访问该savedState字段。我建议,使其无论是封装作用域或使用包范围的访问,并把MyClass与MyListener在同一个包,
PostLoad
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; } }