Java Hibernate@PreUpdate:检查已更改的内容
问题:如何检查用Java Hibernate@PreUpdate:检查已更改的内容,java,hibernate,Java,Hibernate,问题:如何检查用@PreUpdate注释的方法中哪些字段已更改 可选项:如果以上问题的答案是“这是不可能的,那么也许还有其他方法可以解决我的问题” 我希望每次更改旅游者的字段时,都能自动更新已修改的旅游者的字段 除了只修改位置时的情况。意味着如果我们仅更改位置,则应将其保留,但已修改不得更改 已存在代码: @Entity public class Tourist { private long id; private String firstName; private String
@PreUpdate
注释的方法中哪些字段已更改
可选项:如果以上问题的答案是“这是不可能的,那么也许还有其他方法可以解决我的问题” 我希望每次更改
旅游者的字段时,都能自动更新已修改的旅游者的字段
除了只修改位置时的情况
。意味着如果我们仅更改位置
,则应将其保留,但已修改
不得更改
已存在代码:
@Entity
public class Tourist {
private long id;
private String firstName;
private String lastName;
private Date created;
private Date modified;
private String location;
@PreUpdate
public void preUpdate() {
modified = new Date(); //PROBLEM : change modified even if only location field has been changed!
}
....
}
更新:经过一些调查,我发现我可以借助拦截器解决它(扩展EmptyInterceptor
):
但这种方法的缺点是在需要截取单个实体时截取所有内容
更新的问题:
@Entity
public class Tourist {
private long id;
private String firstName;
private String lastName;
private Date created;
private Date modified;
private String location;
@PreUpdate
public void preUpdate() {
modified = new Date(); //PROBLEM : change modified even if only location field has been changed!
}
....
}
- 如何仅拦截旅游实体的同花顺呼叫
- 在事件的帮助下也可以这样做吗?表示包含新状态和旧状态的
PreUpdateEvent
我真的鼓励您不要在您的实体中执行此逻辑
您应该在业务逻辑中决定是否更改修改的
我的意思是,当您仅更改位置调用时,仅合并。无论何时更改其他内容,请调用.setModified(new Date())在调用合并之前执行code>
为了验证是否有任何其他内容发生了更改,我建议在实体
中设置一个瞬态布尔
字段,当您更改位置以外的其他内容时,将该字段设置为true
(注释中的想法不足以测试所有字段,仅当您创建一个临时字段以记住每个字段以前的值时)
然后,您将在您的预更新方法中测试此布尔值
但我强烈不推荐这种解决方法
或者,另一种高度不受赞扬的方式:
@Entity
public class Tourist {
private long id;
private String firstName;
private String lastName;
private Date created;
private Date modified;
private String location;
@Transient
private String firstNamePrevious;
@Transient
private String lastNamePrevious;
@Transient
private Date createdPrevious;
@Transient
private Date modifiedPrevious;
@Transient
private String locationPrevious;
@PreUpdate
public void preUpdate() {
if(!onlyLocationGotChanged()){
modified = new Date();
}
}
....
@PostLoad
public void postLoad(){
//Set all previous fields to actual values
firstNamePrevious = firstName;
lastNamePrevious = lastName;
//...etc.
}
}
有一个简单的非JPA解决方案,如下所示,但它确实有一些重复代码,但在没有太多字段的情况下是一个解决方案:
@Entity
public class Tourist {
private long id;
private String firstName;
private String lastName;
private Date created;
private Date modified;
private String location;
public void setFirstName(String firstName){
if(! this.firstName.equals(firstName){
modified = new Date();
}
this.firstName = firstName;
}
public void setLastName(String lastName){
if(! this.lastName.equals(lastName){
modified = new Date();
}
this.lastName= lastName;
}
}
否则,我会按照另一个答案中的建议,在加载时保存上一个状态,但方式会稍微简单一些
@Entity
public class Tourist {
private long id;
private String firstName;
private String lastName;
private Date created;
private Date modified;
private String location;
@Transient
private Tourist previousState;
@PostLoad
public void setPreviousState() {
previousState = new Tourist();
//copy fields
}
@PreUpdate
public void preUpdate() {
if (isModified()) {
modified = new Date();
}
}
private boolean isModified() {
boolean modified = false;
if (!firstName.equals(previousState.firstName) {
modified = true;
}
//check other fields
return modified;
}
}
虽然已经很晚了,但是我遇到了一个问题,我需要在entity中的某些字段上应用更新安全性。我使用反射解决了这个问题。看看这个线程。为什么不使用一个临时字段来存储以前的位置,并在预更新时在更新修改的字段之前对其进行测试呢建议您创建一个副类,以便跟踪事件(创建、修改等),并在业务级别而不是DAO上更新它level@Hichamov我真的很喜欢你关于额外瞬态场的想法!@Hichamov,但我需要检查其他场是否没有改变。模式详细信息请注意,我以前从未使用过一个。我可能会说一些错误,你是对的,但这个应用程序太大了,我无法确定所有的用法。或者强制ybody需要以正确的方式保存Tourism
实体。因此我正在寻找一些通用的方法。您对EmtpyInterceptor#onFlushDirty有何看法?在业务逻辑中执行此操作的建议无法封装操作。该类的每个客户端都需要知道,它还应该更新修改日期,这非常重要d!我真的不明白它是关于什么的,因为我从未使用过它。但是Object[]newValues
&Object[]oldValues
看起来很漂亮handy@AlanHay我完全同意(我投你一票),这就是我保留其他建议的原因。我只是想指出一下,以防V_BAlso可以使用。请注意,这里的transient关键字在JPA环境中没有任何效果。您要查找的是@transient注释。我有大约20个字段((.您可以看看使用BeanUtils将加载时的数据复制到瞬态实例和保存时的数据来比较两个bean:请看我问题的更新部分好吗?我有一些想法,我不再担心二十个字段,而是开始键入它们。@VB_