在 JPA/Hibernate 中为没有业务键的浅层类层次结构提供对象相等

问题描述

我确信标题可以改进,因此这个问题可能对更广泛的受众有用,但我不确定如何改进。

我正在做一个小型测试项目,试图为表示在服务器和客户端之间交换的消息的实体提供 JPA/Hibernate 持久性(表示消息的类在两个应用程序之间重用,但只有解码的类/由服务器编码将被持久化)。

该协议支持三种类型的交换:

  • 向服务器发送文本,服务器回复 ACK 消息。
  • 向服务器发送一些杂项信息,服务器使用与上面相同的 ACK 消息格式进行回复
  • 向服务器发送带有时区的日期/时间请求,服务器使用该时区的当前日期/时间进行回复

所有消息都具有相同的头部和尾部格式(特别是头部有一个消息类型标识符,尾部有一个校验和字段),以及提到的有效载荷,它们可能在来自相同类型的不同消息中重复,所以它们不足以从持久化上下文中唯一标识给定类型的消息。

请注意,页眉和页脚信息仅与传输上下文相关,因此不需要对它们进行持久化,只需要针对各自的有效负载和一些与持久化相关的唯一标识消息 ID。

我提出了一个类设计,其中包含一个抽象基类以及每个消息类型的一个子类(因此有五个不同的 final 子类),每个子类都有其有效负载字段。除了可能与持久性相关的 id 字段外,基类没有其他字段,以便唯一标识数据库中的消息。

我知道我需要为它们提供适当的 equals()hashCode() 实现,以便将它们添加到基于内存的集合中并持久化它们。

我已决定此层次结构的最佳 O-R 映射是 JOINED 继承策略,它将基本消息表与包含相应负载字段的单个消息表连接起来。因此,基本消息表将有一个自动生成的主键,该主键将映射到抽象消息的 id。

问题实际上有两个方面。基本上我想知道对于这种情况,哪一种应该是更可取的 equals()hashCode() 实现方法,但如果有人对类设计和选择的继承策略有疑虑,我会问也可以让我知道。

因此,为了将其转化为一个有用的问题,我基本上是问在没有原始自我标识(“业务密钥”)的实体的情况下,我应该如何覆盖 equals()hashCode() ) 字段,它们都继承自同一个抽象基类,该类可以包含一个基于持久性的标识符字段。

我打算将其设计为支持具有较新消息类型的较新协议,不一定来自相同的基类(除非我可以使其成为非常通用的基类)。

解决方法

除非您必须查询所有消息,否则我根本不会使用继承映射。就您而言,由于您共享的属性很少,因此最好使用 TABLE_PER_CLASS 策略。

除此之外,我建议您始终根据生成的主键序列实现 equals/hashCode。如果您将新实体(即没有 id 的实体)放入基于散列的集合中,将它们持久化,然后继续使用基于散列的集合,则此方法仅是一个问题。如果不是这种情况,只对 equals/hashCode 使用主键绝对没问题。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...