[英]Should I write equals() and hashCode() methods in JPA entities?
我想检查实体是否在另一个实体的集合成员( @OneToMany
或@ManyToMany
)中:
if (entity2.getEntities1().contains(entity1)) { }
不必要。 共有三个选项:
不要覆盖 - 因此您将使用实例。 如果您使用的集合只有附加到会话的实体(因此保证是相同的实例),这很好。 这是(对我而言)在许多情况下的首选方式,因为它在覆盖时需要更少的代码和更少的考虑
使用业务键覆盖hashCode()
和equals()
。 这可能是标识实体的属性的子集。 例如,对于User
一个好的业务密钥可能是username
或email
。 这被认为是很好的做法。
仅使用 ID 字段覆盖hashCode()
和equals()
。 这在某些情况下很好,特别是如果您有手动分配的标识符(如 UUID)。 如果您的实体永远不会进入集合,那也没关系。 但是对于进入集合的瞬态实体(没有标识符),它会导致问题,所以要小心使用这个选项。 正如 seanizer 指出的那样 - 你应该避免它。 一般来说,总是,除非你真的知道你在做什么(并且可能记录它)
有关更多详细信息,请参阅此文章。 另请注意, equals()
和hashCode()
是绑定的,应该使用完全相同的字段来实现。
是的你应该!
如果您不覆盖默认的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
}
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.