JPA hashCode()/equals()难题

出现了一些此处讨论有关JPA实体以及哪些实体hashCode()/等于()实现应用于JPA实体类。大多数(如果不是全部的话)都依赖于Hibernate,但我想中性地讨论它们JPA实现(顺便说一下,我使用的是EclipseLink)

在以下方面,所有可能的实施都有自己的优点和缺点:

  • hashCode()/equals()针对列表/集合操作的一致性(不变性)
  • 是否可以检测到相同的对象(例如来自不同会话、来自延迟加载数据结构的动态代理)
  • 实体在分离(或非持久化)状态下的行为是否正确

据我所知,有三种选择:

  1. 不要超越它们;依赖Object.equals()Object.hashCode()
    • hashCode()/equals()工作
    • 无法识别相同的对象,动态代理存在问题
    • 分离实体没有问题
  2. 基于主键覆盖它们
    • hashCode()/equals()已损坏
    • 正确标识(适用于所有托管实体)
    • 分离实体的问题
  3. 基于业务Id(非主键字段;外键如何?)
    • hashCode()/equals()已损坏
    • 正确标识(适用于所有托管实体)
    • 分离实体没有问题

我的问题是:

  1. 我是否错过了一个选项和/或赞成/反对的观点?
  2. 你选择了什么选项?为什么

更新1:

通过“hashCode()/equals()被破坏”,我的意思是连续的hashCode()调用可能会返回不同的值,这些值(在正确实现时)在对象API文档的意义上不会被破坏,但是,当尝试从映射或其他基于哈希的集合检索更改的实体时,会出现问题。因此,JPA实现(至少EclipseLink)在某些情况下无法正常工作

更新2:

感谢您的回答,其中大多数都有卓越的品质。
不幸的是,我仍然不确定哪种方法最适合实际应用程序,或者如何确定适合我的应用程序的最佳方法。因此,我将继续讨论这个问题,并希望有更多的讨论和/或意见

阅读这篇关于这个主题的非常好的文章:不要让hibernate窃取您的身份

文章的结论如下:

对象标识在以下情况下很难正确实现
对象被持久化到数据库。然而,问题的根源在于
完全不允许对象在创建之前没有id而存在
保存的。我们可以通过承担责任来解决这些问题
从对象关系映射框架中分配对象ID
比如冬眠。相反,只要
对象被实例化。这使得对象标识变得简单和容易
无错误,并减少域模型中所需的代码量

发表评论