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

问题描述 投票:51回答:6

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

if (entity2.getEntities1().contains(entity1)) { }
java jpa entity equals hashcode
6个回答
115
投票

不必要。有三种选择:

  • 不要覆盖 - 因此您将使用实例。当您使用仅附加到会话的实体(因此保证是相同的实例)处理集合时,这很好。在许多情况下,这是(对我而言)首选方式,因为它在覆盖时需要更少的代码和更少的考虑
  • 使用业务键覆盖hashCode()equals()。这可能是标识实体的属性的子集。例如,对于User,一个好的商业关键可能是usernameemail。这被认为是很好的做法。
  • 仅使用ID字段覆盖hashCode()equals()。在某些情况下这很好,特别是如果您有一个手动分配的标识符(如UUID)。如果您的实体永远不会进入集合,那也没关系。但对于进入集合的瞬态实体(没有标识符),它会导致问题,因此请谨慎使用此选项。正如海员所说 - 你应该避免它。一般来说,除非你真的知道自己在做什么(并且可能记录下来),否则

See this article了解更多详情。另请注意,equals()and hashCode()是绑定的,应该使用完全相同的字段来实现。


15
投票

是的你应该!

如果你没有覆盖默认的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操作将返回一个不同的对象实例,平等合同将被打破as explain in this post

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

@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实现应始终返回与我在上面提到的相同帖子中所述相同的值:

@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 31;
    }

    //Getters and setters omitted for brevity
}

13
投票

是的,你应该定义相应的equals()hashcode()方法,但你永远不应该让id成为其中之一。 (在类似的问题中见this recent answer of mine



5
投票

我们倾向于让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()中的子类。


2
投票

这是唯一的方法。您可能想尝试Pojomatic库,它可以帮到您。

© www.soinside.com 2019 - 2024. All rights reserved.