模型类的 equals 和 hashcode 在 Hibernate 中应该如何实现?常见的陷阱有哪些?默认实现对于大多数情况来说足够好吗?使用业务密钥有任何意义吗?

在我看来,当考虑到延迟获取、id 生成、代理等时,很难让它在每种情况下都正常工作。

有帮助吗?

解决方案

Hibernate对 equals() / hashCode()有很好的描述.org / hibernate / core / 4.0 / manual / en-US / html / persistent-classes.html#persistent-classes-equalshashcode“rel =”noreferrer“> documentation

它的要点是,如果您的实体将成为 Set 的一部分,或者您将要分离/附加其实例,则只需要担心它。后者并不常见。前者通常最好通过以下方式处理:

  1. 基于业务键的 equals() / hashCode() - 例如属性的唯一组合,在对象(或至少是会话)生命周期内不会发生变化。
  2. 如果上述情况不可能,则在主键上设置基本 equals() / hashCode(),如果设置了对象标识/ System.identityHashCode()否则。这里的重要部分是,您需要在添加新实体并坚持后重新加载您的设置;否则你最终可能会遇到奇怪的行为(最终导致错误和/或数据损坏),因为您的实体可能被分配到与其当前 hashCode()不匹配的存储桶。

其他提示

我不认为接受的答案是准确的。

回答原来的问题:

  

对于大多数情况,默认实现是否足够好?

答案是肯定的,在大多数情况下都是。

如果实体将用于 Set (这是非常常见的),您只需覆盖 equals() hashcode() AND 该实体将与hibernate会话分离,并随后重新附加到hibernate会话(这是hibernate的一种罕见用法)。

接受的答案表明,如果 条件为真,则需要覆盖这些方法。

当通过延迟加载加载实体时,它不是基类型的实例,而是由javassist生成的动态生成的子类型,因此检查相同的类类型将失败,因此不要使用:

if (getClass() != that.getClass()) return false;

改为使用:

if (!(otherObject instanceof Unit)) return false;

这也是一种很好的做法,如在Java实践中实现等于

出于同样的原因,直接访问字段,可能无法工作并返回null,而不是基础值,因此不要在属性上使用比较,而是使用getter,因为它们可能会触发加载基础值。

当您使用等于 / hashCode 实现/“rel =”nofollow noreferrer“>唯一的业务密钥

所有实体状态的商家密钥应保持一致转换(瞬态,附加,分离,删除),这就是为什么你不能依赖id来实现平等。

另一个选择是切换到使用由应用程序分配的 UUID标识符逻辑。这样,您可以将UUID用于 equals / hashCode ,因为在刷新实体之前会分配id。

您甚至可以使用 equals hashCode 的实体标识符,但这需要您始终返回相同的 hashCode 值,以便您确保实体hashCode值在所有实体状态转换中保持一致。查看此帖子,了解有关此主题的更多信息

是的,这很难。在我的项目中,equals和hashCode都依赖于对象的id。这个解决方案的问题是,如果对象尚未持久化,它们都不起作用,因为id是由数据库生成的。在我的情况下,这是可以容忍的,因为在几乎所有情况下,对象都会立即存在。除此之外,它工作得很好并且易于实现。

如果你碰巧覆盖了 equals, ,确保您履行其合同:-

  • 对称
  • 反光的
  • 及物
  • 持续的
  • 非空

并覆盖 hashCode, ,因为它的合同依赖于 equals 执行。

Joshua Bloch(Collection框架的设计者)强烈敦促遵守这些规则。

  • 第 9 项:当你覆盖 equals 时,总是覆盖 hashCode

如果您不遵守这些合同,则会产生严重的意外影响。例如 List.contains(Object o) 可能返回错误 boolean 价值为总合同未履行。

在Hibernate 5.2的文档中,它表示你可能根本不想实现hashCode和equals - 具体取决于你的情况。

https:// docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#mapping-model-pojo-equalshashcode

通常,如果在数据库中它们相等(不实现hashCode和equals),则从同一会话加载的两个对象将是相等的。

如果您正在使用两个或更多会话,则会变得复杂。在这种情况下,两个对象的相等性取决于你的equals-method实现。

此外,如果您的equals-method正在比较仅在第一次持久保存对象时生成的ID,则会遇到麻烦。当调用equals时,它们可能不存在。

这里有一篇非常好的文章: 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 
}

}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top