我想检查一个实体是否在另一个实体的集合成员(@OneToMany
或@ManyToMany
)中:
if (entity2.getEntities1().contains(entity1)) { }
查看这篇文章以获取更多详细信息。还请注意,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
实现应始终返回相同的值。对于实体来说,这不是真正的问题,因为您每个数据库事务中不会获取太多实体,否则,获取数据的成本将比使用固定hashCode
带来的单桶HashMap
惩罚大得多:
@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()
方法。
Collection.contains(JpaEntity someObject)
需要一个合理的JpaEntity.equals(...)
方法。 - Abdull