Java 在equals/hashCode/toString中是否应使用@Transient属性?

Java 在equals/hashCode/toString中是否应使用@Transient属性?,java,orm,jpa,transient,Java,Orm,Jpa,Transient,我有JPA实体,其中一些属性用@Transient注释 我应该在equals/hashCode/toString方法中使用这些属性吗 我的第一个想法是不,但我不知道为什么 小费 想法 解释 据我所知,@Transient和Transient的两种典型用法是将它们用于无法序列化/持久化的内容(例如远程资源句柄)或可以从其他内容重建的计算属性 对于计算数据,在相等关系(equals/hashCode)中使用它们是没有意义的,因为这是多余的。该值是从等式中已使用的其他值中计算出来的。但是,在toSt

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

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

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

  • 小费
  • 想法
  • 解释

据我所知,
@Transient
Transient
的两种典型用法是将它们用于无法序列化/持久化的内容(例如远程资源句柄)或可以从其他内容重建的计算属性

对于计算数据,在相等关系(
equals/hashCode
)中使用它们是没有意义的,因为这是多余的。该值是从等式中已使用的其他值中计算出来的。但是,在
toString
中打印它们仍然是有意义的(例如,基本价格和比率用于计算实际价格)

对于不可序列化/可扩展的数据,这取决于。我可以想象一个不可序列化的资源句柄,但是您仍然可以比较句柄所表示的资源名称。对于
toString
,可能打印句柄资源名称很有用

这是我的2美分,但是如果你解释一下你对
@Transient
的特殊用法,也许有人能给你一个更好的建议。

toString()的情况不同,你可以用
toString()
做任何你想做的事,所以我只讨论
equals()
(和
hashCode()

首先,规则是:如果要将对象存储在
列表
映射
集合
中,则需要实现
等于
哈希代码
,以便它们遵守文档中指定的标准约定

现在,如何实现
equals()
hashCode()
?“自然”的想法是使用映射为
Id
的属性作为
equals()
的一部分:

不幸的是,此解决方案存在一个主要问题:当使用生成的标识符时,在实体变得持久之前,不会分配值,因此如果在保存前将临时实体添加到
集合
,当它在
集合
中时,它的哈希代码将发生变化,这将打破
集合
的契约

因此,建议的方法是使用作为业务密钥一部分的属性,即具有相同数据库标识的每个实例的唯一属性组合。例如,对于用户类,这可能是用户名:

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();
  }
}
Hibernate参考文档将其总结如下:

切勿使用数据库标识符来实现相等;请使用业务密钥,即唯一的、通常不可变的属性组合。如果临时对象成为持久对象,则数据库标识符将更改。如果临时实例(通常与分离的实例一起)在
集合
中保存,更改
哈希代码
会破坏
集合
的契约。业务键的属性不必像数据库主键那样稳定,只要对象在同一集合中,您就只需保证稳定性。“-

建议您使用业务密钥相等来实现
equals()
hashCode()
。业务密钥相等意味着
equals()
方法只比较构成业务密钥的属性。它是一个在现实世界中标识实例的密钥(自然候选密钥)”-

那么,回到最初的问题:

  • 如果可能,请使用业务密钥
    @Transient
    属性很可能不是此类密钥的一部分
  • 如果不可能,请使用标识符属性,但确保在将实体添加到
    列表
    映射
    之前获得分配的值
另见
  • 使用Hibernate理解Java持久化中的equals()和hashCode()(第396页)

例外情况可能来自于让它成为
瞬态
,同时提供
writeObject()
readObject()
处理它的位置

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();
  }
}