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

时间:2010-06-01 16:17:43

标签: java orm jpa transient

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

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

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

  • 提示?
  • 想法?
  • 说明

3 个答案:

答案 0 :(得分:6)

toString()的情况不同,您可以使用toString()执行任何操作,因此我只会涵盖equals()(和hashCode())。

首先,规则:如果您想要在ListMapSet 中存储对象,则需要{{1 }和equals已实施,因此他们遵守文档中指定的标准合同。

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

equals()

不幸的是,此解决方案存在主要问题:使用生成的标识符时,在实体变为持久之前不会分配值,因此如果瞬态 entity在保存之前被添加到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的约定。

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

Set

Hibernate参考文档总结如下:

  

永远不要使用数据库标识符来实现相等性;使用业务键,唯一的,通常是不可变的属性的组合。如果瞬态对象是持久的,数据库标识符将会改变。瞬态实例(通常与分离的实例一起)保存在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(); } } 中,更改Set会破坏hashcode的合约。业务键的属性不必像以下那样稳定数据库主键,只要对象在同一个Set中,你就必须保证稳定性。“ - 12.1.3. Considering object identity

     

建议您使用业务密钥相等实施Setequals()。业务密钥相等意味着hashCode()方法仅比较属性形成业务密钥。它是识别我们在现实世界中的实例的关键(自然候选键)“ - 4.3. Implementing equals() and hashCode()

所以,回到最初的问题:

  • 尽可能使用商家密钥。 equals()属性很可能不是此类密钥的一部分。
  • 如果不可能,请使用标识符属性,但请务必获取之前指定的值,以便将实体添加到@TransientListMap

另见

答案 1 :(得分:0)

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

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

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

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

答案 2 :(得分:0)

例外情况可能来自让transient,同时您提供处理它的writeObject()readObject()