Hibernate @PreUpdate:检查已更改的内容

VB_*_*VB_ 4 java hibernate

问题: 如何检查用 注释的方法内哪些字段已更改@PreUpdate


可选:如果上述问题的答案是“不可能,那么也许还有其他方法可以解决我的问题”

我希望modified Tourist每次更改其中的内容时自动更新的字段。

除了我们只修改的情况location。意味着如果我们location只改变——它应该被坚持,但modified不能改变。

已经存在的代码:

@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!
  }   
  ....
}
Run Code Online (Sandbox Code Playgroud)

更新:经过一些调查,我发现我可以在拦截器的帮助下解决它(扩展EmptyInterceptor):

public class TouristInterceptor extends EmptyInterceptor{

    Session session;
    private Set updates = new HashSet();

    public void setSession(Session session) {
        this.session=session;
    }

    public boolean onFlushDirty(Object entity,Serializable id,
        Object[] currentState,Object[] previousState,
        String[] propertyNames,Type[] types)
        throws CallbackException {

        if (entity instanceof Tourist){
            if (somethingChangedExceptLocation()) 
                updates.add(entity);
        }
        return false;
    }
Run Code Online (Sandbox Code Playgroud)

但这种方法的缺点是当您需要拦截单个实体时,会拦截所有内容。

更新的问题:

  • 如何仅拦截旅游实体刷新调用?
  • 在事件的帮助下可以做同样的事情吗?表示PreUpdateEvent包含新状态和旧状态

Ala*_*Hay 5

有一个简单的非 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

否则,我会按照另一个答案中的建议,以稍微干净的方式保存加载时的先前状态。

@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;
  }
}
Run Code Online (Sandbox Code Playgroud)