Answers:
Hibernate有何时/如何重写一个很好的和长期的描述equals()
/ hashCode()
在文档
要点是,如果您的实体将成为a的一部分,Set
或者您要分离/附加其实例,则只需要担心它。后者并不常见。前者通常最好通过以下方式处理:
equals()
/ hashCode()
基于业务密钥-例如,在对象(或至少会话)生存期内不会改变的属性的唯一组合。equals()
/ hashCode()
对主键如果它被设置和对象标识/ System.identityHashCode()
否则。这里的重要部分是您需要在将新实体添加到其中并保留之后重新加载您的Set;否则,您可能会遇到奇怪的行为(最终导致错误和/或数据损坏),因为您的实体可能会分配给与当前桶不匹配的存储桶hashCode()
。refresh()
?遵守Set
合同的实体会如何落入错误的存储桶中(假设您具有足够好的哈希码实现)。
Set.contains(entity)
然后您会回来false
。同样适用于get()/ put()/等...
我认为接受的答案不正确。
要回答原始问题:
默认实现在大多数情况下是否足够好?
答案是肯定的,在大多数情况下是这样。
你只需要重写equals()
和hashcode()
该实体将被用在Set
(这是很常见)和该实体将与休眠会话分离,然后再重新附加到休眠会话(这是休眠的一种罕见用法),则只需重写。
接受的答案表明,如果任一条件为真,则需要覆盖这些方法。
最好的equals
/ hashCode
实施方法是使用唯一的业务密钥。
业务密钥在所有实体状态转换(瞬态,附加,分离,删除)之间应该保持一致,这就是为什么不能依靠id来实现相等性的原因。
另一个选择是切换到使用由应用程序逻辑分配的UUID标识符。这样,您可以将UUID用作equals
/,hashCode
因为在刷新实体之前已分配ID。
您甚至可以将实体标识符用于equals
和hashCode
,但是这要求您始终返回相同的hashCode
值,以确保实体hashCode值在所有实体状态转换之间都是一致的。请查看此帖子以获取有关此主题的更多信息。
BaseEntity
,再也不要考虑这个问题了。在数据库侧需要一些空间,但是您最好为舒适度付出代价:)
通过延迟加载加载实体时,它不是基本类型的实例,而是由javassist生成的动态生成的子类型,因此对同一类类型的检查将失败,因此请不要使用:
if (getClass() != that.getClass()) return false;
改为使用:
if (!(otherObject instanceof Unit)) return false;
正如在Java实践中实现平等所解释的,这也是一个好习惯。
由于相同的原因,直接访问字段可能无法工作并返回null而不是基础值,因此不要对属性使用比较,而要使用getter,因为它们可能触发加载基础值。
是的,很难。在我的项目中,equals和hashCode都依赖于对象的ID。该解决方案的问题在于,如果该对象尚未持久化,则它们都不起作用,因为该ID是由数据库生成的。在我的情况下,这是可以容忍的,因为在几乎所有情况下,对象都是立即保留的。除此之外,它的工作原理非常好并且易于实现。
在Hibernate 5.2的文档中,它说您可能不希望实现hashCode并且完全等于-取决于您的情况。
通常,如果在数据库中相等,则从同一会话加载的两个对象将相等(不实现hashCode和equals)。
如果您使用两个或多个会话,它将变得很复杂。在这种情况下,两个对象的相等性取决于您的equals-method实现。
此外,如果您的equals-method比较仅在第一次持久存储对象时生成的ID,您会遇到麻烦。当调用equals时,它们可能还不存在。
这里有一篇很好的文章:https : //docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html
引用文章中的重要内容:
我们建议使用业务键相等性来实现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
}
}
如果您碰巧要超越equals
,请确保您履行其合同:-
并覆盖hashCode
,因为其合同依赖equals
实施。
Joshua Bloch(集合框架的设计者)强烈敦促遵守这些规则。
不遵守这些合同会产生严重的意想不到的影响。例如,由于未履行总合同,List#contains(Object o)
可能返回错误的boolean
值。