繁体   English   中英

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

[英]Should @Transient property be used in equals/hashCode/toString?

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

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

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

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

toString()情况不同,你可以用toString()做任何你想要的事情,所以我只会覆盖equals() (和hashCode() )。

首先,规则: 如果要将对象存储在ListMapSet ,则需要实现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();
  }
}

不幸的是,这个解决方案有一个主要问题 :当使用生成的标识符时,在实体变为持久化之前不会分配值,因此如果在保存之前将一个瞬态实体添加到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();
  }
}

Hibernate参考文档总结如下:

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

建议您使用Business键相等来实现equals()hashCode() 。业务键相等性意味着equals()方法仅比较构成业务键的属性。它是一个用于标识我们的实例的键。现实世界(自然候选键)“ - 4.3。 实现equals()和hashCode()

那么,回到最初的问题:

  • 如果可能,请使用业务密钥。 @Transient属性很可能不属于这样一个键。
  • 如果不可能,请使用标识符属性,但请确保在将实体添加到ListMapSet之前获取指定的值。

也可以看看

异常可能来自于让它是transient ,同时你提供writeObject()readObject()处理它。

我所知道的@Transienttransient的两个典型用法是将它们用于无法序列化/持久化的东西(例如远程资源句柄 )或可以从其他人重建的计算属性。

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

对于不可序列化/可持久化的数据 ,它取决于。 我可以想象一个不可序列化的资源的句柄,但你仍然可以比较句柄所代表的资源名称。 对于toString ,也许打印句柄资源名称很有用。

这是我的2美分,但如果你解释你对@Transient的特殊用法,有人可以提供更好的建议。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM