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
Should I write equals() and hashCode() methods in JPA entities?
提问by j2j
I want to check if entity is in a Collection member (@OneToMany
or @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()
andequals()
with a business key. That may be a subset of properties that identify the entity. For example, for aUser
a good business key might be theusername
or theemail
. This is considered good practice.override
hashCode()
andequals()
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
好的业务键可能是username
或email
。这被认为是很好的做法。仅覆盖
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?
回答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_7
in 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.Object
equals
and hashCode
implementation:
如果您不覆盖默认值Java.lang.Object
equals
和hashCode
实现:
@Entity(name = "Book")
public class Book implements Identifiable<Long> {
@Id
@GeneratedValue
private Long id;
private String title;
//Getters and setters omitted for brevity
}
the merge
operation 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
}