繁体   English   中英

我应该在 JPA 实体中编写 equals() 和 hashCode() 方法吗?

[英]Should I write equals() and hashCode() methods in JPA entities?

我想检查实体是否在另一个实体的集合成员( @OneToMany@ManyToMany )中:

if (entity2.getEntities1().contains(entity1)) { }

不必要。 共有三个选项:

  • 不要覆盖 - 因此您将使用实例。 如果您使用的集合只有附加到会话的实体(因此保证是相同的实例),这很好。 这是(对我而言)在许多情况下的首选方式,因为它在覆盖时需要更少的代码和更少的考虑

  • 使用业务键覆盖hashCode()equals() 这可能是标识实体的属性的子集。 例如,对于User一个好的业务密钥可能是usernameemail 这被认为是很好的做法。

  • 仅使用 ID 字段覆盖hashCode()equals() 这在某些情况下很好,特别是如果您有手动分配的标识符(如 UUID)。 如果您的实体永远不会进入集合,那也没关系。 但是对于进入集合的瞬态实体(没有标识符),它会导致问题,所以要小心使用这个选项。 正如 seanizer 指出的那样 - 你应该避免它。 一般来说,总是,除非你真的知道你在做什么(并且可能记录它)

有关更多详细信息,请参阅此文章 另请注意, equals()hashCode()是绑定的,应该使用完全相同的字段来实现。

是的你应该!

如果您不覆盖默认的Java.lang.Object equalshashCode实现:

@Entity(name = "Book")
public class Book implements Identifiable<Long> {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private String title;
 
    //Getters and setters omitted for brevity
}

merge操作将返回一个不同的对象实例,平等契约将被打破。

最好的方法是使用业务密钥,如下所示:

@Entity
public class Book implements Identifiable<Long> {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private String title;
 
    @NaturalId
    private String isbn;
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Book)) return false;
        Book book = (Book) o;
        return Objects.equals(getIsbn(), book.getIsbn());
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(getIsbn());
    }
 
    //Getters and setters omitted for brevity
}

您也可以使用标识符来表示相等,但请注意hashCode实现应始终返回相同的值,这对于实体来说并不是真正的问题,因为您不会为每个 DB 事务获取许多实体,否则,获取数据的成本比使用固定hashCode施加的单桶HashMap惩罚大hashCode

@Entity
public class Book implements Identifiable<Long> {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private String title;
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Book)) return false;
        Book book = (Book) o;
        return Objects.equals(getId(), book.getId());
    }
 
    @Override
    public int hashCode() {
        return getClass().hashCode();
    }
 
    //Getters and setters omitted for brevity
}

是的,你应该定义相应的equals()hashcode()方法,但你不应该让 id 成为其中的一部分。 (请参阅我最近在类似问题中的回答)

我们倾向于让 IDE 为我们生成hashCode()equals() 不过要小心。 当您为 JPA 实体生成这些方法时。 某些版本的equals()检查类标识

// ... inside equals() - wrong approach for Entities (cause of generate proxies)
if (o == null || this.getClass() != o.getClass()) {
        return false;
}
// ...

这会破坏一些 JPA 库的集合,因为这些库会创建实体(子类)的代理,例如 Hibernate 中的MyGreatEntity_$$_javassist_7

在实体中总是允许子类在equals()

这是唯一的办法。 您可能想尝试为您完成艰苦工作的Pojomatic库。

暂无
暂无

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

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