JPA/Hibernate - 通过超类查询时如何确定子类类型?

aro*_*oth 5 java hibernate jpa

我刚刚注意到 Hibernate 中的这种行为,并发现它有点令人惊讶(以一种受欢迎的方式)。我有一个名为的实体类型SyncItem,它充当许多其他实体的超类。继承策略设置为InheritanceType.JOINED,超类中的所有字段都有一个表,而子类表仅包含子类中添加的任何内容的字段,以及对超类表的引用。

例如,我的SyncItem表格如下所示:

mysql> describe syncItems;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| hidden     | bit(1)       | NO   |     | NULL    |                |
| title      | varchar(255) | NO   |     | NULL    |                |
| createDate | datetime     | NO   |     | NULL    |                |
| modifyDate | datetime     | YES  |     | NULL    |                |
| deleteDate | datetime     | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
Run Code Online (Sandbox Code Playgroud)

如果我有一个Property子类,它可能会得到一个像这样的表:

mysql> describe properties;
+--------------+--------------+------+-----+---------+-------+
| Field        | Type         | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| syncId       | bigint(20)   | NO   | PRI | NULL    |       |
| propertyCode | varchar(255) | YES  |     | NULL    |       |
+--------------+--------------+------+-----+---------+-------+
Run Code Online (Sandbox Code Playgroud)

现在我有大约十几个不同的子类,令我惊讶的是我有一个如下查询:

@NamedQuery(
    name="SyncItem.findByTitle", 
    query="SELECT s FROM SyncItem s WHERE s.title = :title")
Run Code Online (Sandbox Code Playgroud)

当我写这篇文章时,我期望因为我选择 from SyncItem,所以我只会返回超类表中包含的信息(即我会得到一个SyncItem实例,而不是一个Property实例)。然而,当我运行它时,我发现查询实际上返回了正确的子类实​​例。这很好,因为它使许多事情更容易实施。

但是,我想知道,JPA/Hibernate 如何设法恢复子类?它无法知道给定的标题将映射到 aProperty而不会映射到其他内容,并且据我所知,它没有从syncItemsto的直接映射properties(相反,它必须从propertiesto映射回syncItems)。当执行此查询时,它是否与每个子类表进行连接?如果是这样,那么查询是否会变得非常昂贵?

所以是的,只是想知道幕后发生了什么。

Mr.*_*art 4

是的,它对每个子表执行 Join。它很昂贵,但您可以使用其他两种策略中的任何一种来映射继承。

您可以在此处找到说明此内容的参考:

联合策略通常是继承模型中最慢的。检索任何子类需要一个或多个数据库连接,而存储子类需要多个 INSERT 或 UPDATE 语句

3 种可用策略中的每一种都有其自身的优点和缺点(如果您更喜欢节省空间而不是时间,或者两者之间的折衷方案)。选择还取决于您将更频繁地在这些表上执行的操作类型。在我粘贴的参考文献中,您会发现每个参考文献都有相当好且简单的解释。