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