Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Hibernate@PreUpdate:检查已更改的内容_Java_Hibernate - Fatal编程技术网

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_