应该在equals/hashCode/toString中使用@Transient属性吗?

raf*_*ira 8 java orm jpa transient

我有JPA实体,其中一些属性注释@Transient.

我应该在equals/hashCode/toString方法中使用这些属性吗?

我的第一个想法是不,但我不知道为什么.

  • 提示?
  • 想法?
  • 解释吗?

Pas*_*ent 7

情况toString()不同,你可以随心所欲,toString()所以我只会覆盖equals()(和hashCode()).

首先,规则:如果你想存储对象的List,MapSet 则是一个要求equalshashCode实施,使他们遵守的标准合同文件中指定.

现在,如何实施equals()hashCode()?一个"自然"的想法是使用映射的属性Id作为以下内容的一部分equals():

public class User {
    ...
    public boolean equals(Object other) {
        if (this==other) return true;
        if (id==null) return false;
        if ( !(other instanceof User) ) return false;
        final User that = (User) other;
        return this.id.equals( that.getId() );
    }
    public int hashCode() {
        return id==null ? System.identityHashCode(this) : id.hashCode();
  }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这个解决方案有一个主要问题:当使用生成的标识符时,在实体变为持久化之前不会分配这些值,因此如果在保存之前将瞬态实体添加到a Set中,则其哈希代码将在其中进行更改Set并且会中断合同Set.

因此,推荐的方法是使用属于业务键的属性,即对于具有相同数据库标识的每个实例唯一的属性组合.例如,对于User类,这可以是用户名:

public class User {
    ...
    public boolean equals(Object other) {
        if (this==other) return true;
        if ( !(other instanceof User) ) return false;
        final User that = (User) other;
        return this.username.equals( that.getUsername() );
    }
    public int hashCode() {
        return username.hashCode();
  }
}
Run Code Online (Sandbox Code Playgroud)

Hibernate参考文档总结如下:

" 永远不要使用数据库标识符来实现相等性;使用业务键,唯一的,通常是不可变的属性的组合.如果瞬态对象是持久的,数据库标识符将会改变.如果瞬态实例(通常与分离的实例一起)是保存在a中Set,更改hashcode中断的合同Set.业务键的属性不必像数据库主键一样稳定,只要对象在同一个Set中,就必须保证稳定性.- 12.1.3.考虑对象身份

" 建议您实现equals()hashCode()使用Business密钥相等.业务密钥相等意味着该equals()方法仅比较构成业务密钥的属性.它是识别我们在现实世界中的实例的密钥(自然候选密钥)" - 4.3.实现equals()和hashCode()

那么,回到最初的问题:

  • 如果可能,请使用业务密钥.@Transient属性很可能不属于这样一个关键.
  • 如果没有可能,使用标识属性,但一定要得到之前分配给实体添加到一个值List,Map,Set.

也可以看看