java - 我可以在 equals/hashCode 中使用实体的 ID 并回退到实例相等性吗?

标签 java jpa equals hashcode

鉴于我的特定使用模式,我试图弄清楚这种方法有什么问题:

@Entity
public class DomainObject {
  @Id // + sequence generator
  private Long id;

  @Override
  public boolean equals(Object o) {
    // bunch of other checks omitted for clarity
    if (id != null) { 
      return id.equals(o.getId());
     }
     return super.equals(o);
  }

  @Override
  public int hashCode() { 
    if (id != null) {
      return id.hashCode();
    } 
    return super.hashCode();
}

我已经阅读了关于这个主题的几篇文章,听起来您不想在 equals/hashCode 中使用数据库生成的序列值,因为在对象被持久化之前它们不会被设置,而您不想希望不同的 transient 实例都是平等的,否则持久层本身可能会崩溃。

但是回退到临时对象的默认 Object equals/hashCode(实例相等性)然后在您拥有它时使用生成的 @Id 有什么问题吗?

我能想到的最糟糕的事情是,一个 transient 对象永远不能等于一个持久对象,这在我的用例中很好——这是我唯一一次将对象放入集合中并想要 contains 来工作,所有的对象都已经是持久化的并且都有 ID。

但是,我觉得在持久层的深处还有其他一些非常微妙、不明显的错误,但我不太清楚是什么。

其他选项似乎也没有那么吸引人:

  • 无所事事并接受实例相等性(默认 Object.equals):对我的大多数实体来说效果很好,但是当我想要一个包含分离实体的集合时,我厌倦了少数情况下的变通方法(例如, session 范围)和来自当前交易的“实时”范围

  • 使用业务键:我有明确的自然键,但它们是可变的,这会 一些和上面相同的问题(hashCode stability if object changes)

  • 使用 UUID - 我知道这会起作用,但是用工件污染数据库以支持 java.util 集合感觉不对。

另见:

最佳答案

javadoc of Map写道:

Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.

只要对象被持久化,你的实现就会改变 equals 的含义。因此,包含该对象的任何集合都不再需要正常工作。特别是,更改用作 HashMap(或包含在 HashSet 中)中的键的对象的哈希码可能会导致将来对该 Map(Set)的查找找不到该对象,并将该对象再次添加到 Map(Set)很可能会成功,即使在一般情况下,一个 Map 可能最多包含每个给定键的一个映射,而一个 Set 最多包含每个对象一次。

由于将实体存储在集合中(以表达 ToMany 关联)很常见,因此该缺陷很可能会导致实际难以发现的错误。

因此,我强烈建议不要根据数据库生成的标识符实现哈希码。

关于java - 我可以在 equals/hashCode 中使用实体的 ID 并回退到实例相等性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13337595/

相关文章:

用于检查传入请求的 HTTP header 的 Java 代码

java - 我应该重写 Object.equals(Object) 方法吗?

Java 集合 - 重写 equals 和 hashCode

hibernate - JPA 2 条件查询在 select 语句中的 FK 问题的表达式中,其中 n 是 #values

java - JDBCSQL异常: Column not found [@Column annotation is not working field in JPA]

c# - 重写相等运算符

java - 二级缓存 : Spring 3. 2.2 + Hibernate 4.2.0 Infinispan

Java,如何拆分列表的元素?

java - 合并/捆绑 DLL/LIB (C++/Java)

Spring Jpa 将自定义功能添加到所有存储库,同时将其他自定义功能添加到单个存储库