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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4388360/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 16:50:03  来源:igfitidea点击:

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

javajpaentityequalshashcode

提问by j2j

I want to check if entity is in a Collection member (@OneToManyor @ManyToMany) of another entity:

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

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

采纳答案by Bozho

Not necessarily. There are three options:

不必要。共有三个选项:

  • don't override - thus you will be working with instances. This is fine in cases when you are working with the collections with only entities that are attached to the session (and hence guaranteed to be the same instance). This is (for me) the preferred way in many cases, because it requires less code and less consideration when overriding

  • override hashCode()and equals()with a business key. That may be a subset of properties that identify the entity. For example, for a Usera good business key might be the usernameor the email. This is considered good practice.

  • override hashCode()and equals()using the ID field only. This is fine in some cases, especially if you have a manually-assigned identifier (like an UUID). It is also fine if your entity will never go into a collection. But for transient entities (with no identifier) that go into collections, it causes problems, so careful with this option. As seanizer noted - you should avoid it. Generally, always, unless you are really aware of what you are doing (and perhaps documenting it)

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

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

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

See this articlefor more details. Also note that equals()and hashCode()are tied and should be implemented both with exactly the same fields.

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

回答by Boris Pavlovi?

That's the only way. You may want to try Pojomaticlibrary which does the hard job for you.

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

回答by Sean Patrick Floyd

Yes, you should define corresponding equals()and hashcode()methods, but you should NEVER let the id be part of either. (See this recent answer of minein a similar question)

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

回答by zbig

We tend to let IDE generate hashCode()and equals()for us. Be careful though. When you generate those methods for JPA Entities. Some versions of equals()checks for class identity

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

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

This would break your collections with some JPA libraries as those libraries create proxies to your entities (subclasses), like for example MyGreatEntity_$$_javassist_7in Hibernate.

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

In Entities always allow subclasses in equals().

在实体中始终允许equals().

回答by Vlad Mihalcea

Yes, you should!

是的你应该!

If you don't override the default Java.lang.Objectequalsand hashCodeimplementation:

如果您不覆盖默认值Java.lang.ObjectequalshashCode实现:

@Entity(name = "Book")
public class Book implements Identifiable<Long> {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    //Getters and setters omitted for brevity
}

the mergeoperation will return a different object instance and the equality contract is going to be broken as explain in this post.

merge操作将返回一个不同的对象实例,并且平等契约将被破坏,如本文所述

The best way is to use a business key, like this:

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

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

You can also use the identifier for equality, but mind that the hashCode implementation should always return the same value as explained in the same post that I already mentioned:

您也可以使用标识符来表示相等,但请注意 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
}