如何在Hibernate中实现模型类的equals和hashcode?常见的陷阱是什么?对于大多数情况,默认实现是否足够好?使用商业密钥有什么意义吗?
在我看来,在考虑延迟提取,id生成,代理等时,很难在任何情况下都能正常工作。
答案 0 :(得分:63)
Hibernate对{/ 3}}
中何时/如何覆盖equals()
/ hashCode()
有很好的描述
它的要点是,如果您的实体将成为Set
的一部分,或者您将要分离/附加其实例,则只需要担心它。后者并不常见。前者通常最好通过以下方式处理:
equals()
/ hashCode()
- 例如属性的唯一组合,在对象(或至少是会话)生命周期内不会发生变化。equals()
/ hashCode()
,如果设置为System.identityHashCode()
,则对象标识为hashCode()
。这里的重要部分是,您需要在添加新实体并坚持后重新加载您的设置;否则您最终可能会遇到奇怪的行为(最终导致错误和/或数据损坏),因为您的实体可能被分配到与其当前{{1}}不匹配的存储桶。答案 1 :(得分:33)
我不认为接受的答案是准确的。
回答原来的问题:
对于大多数情况,默认实现是否足够好?
答案是肯定的,在大多数情况下都是。
如果实体将用于equals()
(这是非常常见的) AND ,则您只需要覆盖hashcode()
和Set
hibernate会话分离,然后重新附加到hibernate会话(这是一种不常见的hibernate用法)。
接受的答案表明,如果 条件为真,则需要覆盖这些方法。
答案 2 :(得分:12)
当通过延迟加载加载实体时,它不是基类型的实例,而是由javassist生成的动态生成的子类型,因此对同一类类型的检查将失败,因此不要使用:
if (getClass() != that.getClass()) return false;
改为使用:
if (!(otherObject instanceof Unit)) return false;
这也是一种很好的做法,如Implementing equals in Java Practices所述。
出于同样的原因,直接访问字段,可能无法工作并返回null,而不是基础值,因此不要在属性上使用比较,而是使用getter,因为它们可能会触发加载基础值。
答案 3 :(得分:10)
最佳equals
/ hashCode
实施是在您使用unique business key时。
商家密钥应该在所有entity state transitions(暂时的,附加的,分离的,已删除的)中保持一致,这就是为什么您不能依赖id进行平等的原因。
另一种选择是切换到使用由应用程序逻辑分配的UUID identifiers。这样,您可以将UUID用于equals
/ hashCode
,因为在刷新实体之前已分配了ID。
您甚至可以使用equals
和hashCode
的实体标识符,但这要求您始终返回相同的hashCode
值,以确保实体hashCode值一致跨所有实体状态转换。查看this post for more on this topic。
答案 4 :(得分:6)
是的,这很难。在我的项目中,equals和hashCode都依赖于对象的id。这个解决方案的问题是,如果对象尚未持久化,它们都不起作用,因为id是由数据库生成的。在我的情况下,这是可以容忍的,因为在几乎所有情况下,对象都会立即存在。除此之外,它工作得很好并且易于实现。
答案 5 :(得分:2)
如果您碰巧覆盖equals
,请确保履行合同: -
并覆盖hashCode
,因为其合同依赖于equals
实施。
Joshua Bloch(Collection框架的设计者)强烈敦促遵守这些规则。
如果您不遵守这些合同,会产生严重的意外影响。例如,List.contains(Object o)
可能会返回错误的boolean
值,因为未达到一般合同。
答案 6 :(得分:1)
在Hibernate 5.2的文档中,它表示你可能根本不想实现hashCode和equals - 具体取决于你的情况。
通常,如果在数据库中它们相等(不实现hashCode和equals),则从同一会话加载的两个对象将是相等的。
如果您正在使用两个或更多会话,则会变得复杂。在这种情况下,两个对象的相等性取决于你的equals-method实现。
此外,如果您的equals-method正在比较仅在第一次持久保存对象时生成的ID,则会遇到麻烦。当调用equals时,它们可能不存在。
答案 7 :(得分:0)
这里有一篇非常好的文章:https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html
引用文章中的重要一行:
我们建议使用Business key实现equals()和hashCode() 平等。业务键平等意味着equals()方法 仅比较形成业务键的属性,即键 将识别我们在现实世界中的实例(一个自然的候选人 键):
简单来说
public class Cat {
...
public boolean equals(Object other) {
//Basic test / class cast
return this.catId==other.catId;
}
public int hashCode() {
int result;
return 3*this.catId; //any primenumber
}
}