我正在努力弄清楚这种方法有什么问题,考虑到我的特定使用模式:
@Entity
public class DomainObject {
@Id // + sequence generator
private Long id;
@Override
public boolean equals(Object o) {
// bunch of other checks omitted for clarity
if (id != null) {
return id.equals(o.getId());
}
return super.equals(o);
}
@Override
public int hashCode() {
if (id != null) {
return id.hashCode();
}
return super.hashCode();
}
我已经阅读了几篇关于这个主题的文章,听起来你不想在equals/hashCode中使用数据库生成的序列值,因为它们直到对象被持久化后才会设置,你不希望不同的瞬态实例都相等,否则持久化层本身可能会出问题。
但是,对于瞬态对象,回退到默认的Object equals/hashCode(实例相等)是否有问题,并在有时使用生成的@Id?
我能想到的最糟糕的事情是,瞬态对象永远无法等于持久对象,在我的用例中没问题 - 我唯一需要将对象放入集合并希望
contains
工作的时间,所有对象都已经持久化并且都有ID。然而,我觉得还有其他一些微妙、不明显的问题存在于持久化层中,但我无法完全理解是什么。
其他选项似乎也不那么吸引人:
什么也不做,使用实例相等性(默认Object.equals):对于我的大多数实体来说效果很好,但在我想要一个包含脱离的实体(例如会话范围)和当前事务中的“活动”实体混合的集合时,需要解决一些问题。
使用业务键:我有清晰的自然键,但它们是可变的,这将具有与上述相同的问题(如果对象更改,则hashCode稳定性)
使用UUID-我知道这样做可以解决问题,但感觉在污染DB以支持java.util集合方面不太对。
另请参阅:
hashCode
返回常量值会破坏HashMap
、HashSet
等的性能特征,把所有对象放在同一个哈希桶中,但这是个好观点。 - wrschneider