10

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

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

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

  • 尖端?
  • 想法?
  • 解释?
4

3 回答 3

7

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

首先,规则:如果你想将一个对象存储在 a或 a中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();
  }
}

不幸的是,这个解决方案有一个主要问题:当使用生成的标识符时,在实体变得持久之前不会分配值,因此如果在保存之前将瞬态实体添加到 aSet中,它的哈希码会在它位于时发生变化,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 参考文档总结如下:

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

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

那么,回到最初的问题:

  • 如果可能,请使用业务密钥。@Transient属性很可能不是这样一个键的一部分。
  • 如果不可能,请使用标识符属性,但确保获取之前分配的值以将实体添加到List, Map, Set

也可以看看

于 2010-06-01T19:00:19.077 回答
0

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

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

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

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

于 2010-06-01T17:52:57.763 回答
0

例外可能来自让它存在transient,同时您提供 writeObject()readObject()处理它的位置。

于 2012-05-09T07:57:31.520 回答