15

为什么在某些继承和多态关联的情况下是必要的@ForceDiscriminator或等效的?@DiscriminatorOptions(force=true)这似乎是完成工作的唯一方法。有什么理由不使用它吗?

4

4 回答 4

13

当我一次又一次地讨论这个问题时,我认为这可能有助于澄清:首先,Hibernate 在使用JOINED_TABLE映射时确实不需要歧视。但是,它在使用时确实需要它SINGLE_TABLE。更重要的是,其他 JPA 提供者大多确实需要它。

当执行多态JOINED_TABLE查询时,Hibernate 实际所做的是创建一个动态命名的鉴别clazz器,使用一个 case-switch 在外连接继承树中涉及的所有表后检查具体子类的唯一字段的存在。将"hibernate.show_sql"属性包含在您的persistence.xml. 在我看来,这可能是JOINED_TABLE查询的完美解决方案,所以 Hibernate 的人吹嘘它是对的。

执行更新和删除时,情况有所不同;这里 hibernate 首先查询您的根表以查找与语句的 where 子句匹配的任何键,并pkTable从结果中创建一个虚拟。然后它"DELETE FROM / UPDATE table WHERE pk IN pkTable"为您的继承树执行任何具体类;IN 运算符会导致O(log(N))每个扫描的表条目的子查询,但它可能在内存中,因此从性能角度来看并不算太糟糕。

为了回答您的具体问题,Hibernate 在这里根本没有看到问题,从某个角度来看,它们是正确的。他们很容易@DiscriminatorValue通过在 期间注入鉴别器值来简单地尊重注释entityManager.persist(),即使他们实际上并没有使用它们。然而,不尊重鉴别器列JOINED_TABLE有优势(对于 Hibernate),可以创建一个温和的供应商锁定案例,甚至可以通过指向卓越的技术来辩护。

@ForceDiscriminator或者@DiscriminatorOptions(force=true)肯定有助于减轻一点痛苦,但是您必须在创建第一个实体之前使用它们,或者被迫使用 SQL 语句手动添加缺失的鉴别器值。如果你敢于离开 Hibernate,它至少会花费你一些代码更改来删除这些 Hibernate 特定的注释,从而产生对迁移的阻力。在这种情况下,这显然是 Hibernate 关心的全部内容。

以我的经验,厂商锁定是每个市场领导者最疯狂的梦想的天堂,因为它是不费吹灰之力保护市场份额的权贵魔杖;因此,只要客户不反击并向供应商施加高于所获得收益的价格,就会这样做。谁说开源世界会有所不同?

ps,只是为了避免任何混淆:我绝不隶属于任何 JPA 实现者。

pps:我通常会在迁移之前忽略这个问题;SQL UPDATE ... FROM然后,您可以使用 Hibernate 用来填充缺失的鉴别器值的相同 case-switch-with-outer-joins 技巧来制定语句。一旦你了解了基本原理,这实际上很容易。

于 2013-12-31T05:11:46.287 回答
6

伙计们让我试着解释一下@DiscriminatorOptions(Force=true)。好吧,它用于单表继承,我最近在其中一个场景中使用了它。我有两个实体映射到单个表。当我试图获取一个实体的记录时,我得到了包含来自这两个实体的记录的结果列表,这是我的问题。为了解决这个问题,我使用 @DiscriminatorOptions(Force=true)了它将使用 Discriminator 列创建谓词,并将指定的值映射到相应的实体。所以我使用后查询将如下所示@DiscriminatorOptions(Force=true)

select * 
from TABLE 
where  YOUR PREDICATE AND DiscriminatorColumn = DiscriminatorValue
于 2014-01-09T14:13:09.960 回答
3

我认为这更多是我的观点,但我认为有些人会同意我的看法。我更喜欢 Hibernate 使您不使用鉴别​​器这一事实。在某些情况下,鉴别器是不必要的。

例如,我有一个Person实体,其中包含姓名、出生日期等内容。该实体可以被其他几个实体使用,例如Employeeor Customer。当我不Person从其他实体引用,而是引用EmployeeorCustomer时,不使用鉴别​​器,因为 Hibernate 被指示获取任何一个。

于 2012-08-31T05:34:01.920 回答
-1

@yannisf ForceDiscriminator 不是解决此问题的唯一解决方案。

您可以为每个子类进行 instanceof 测试。虽然这就像在代码中对类进行硬编码,但如果没有填充鉴别器列,这是解决问题的一种更简洁的方法。

这也有助于您的代码避免混合 jpa 和 hibernate 注释。

正如yannisf 所指出的,instanceOf 是OO 世界中的一种反模式。

另一种解决方案可能是更改您的实体映射。假设一个实体 A 有一个对超类 B 的引用,而 B 有 C1 和 C2 类型的子类,那么您可以让 C1 和 C2 有一个指向 A 的外键,而不是 A 指向 B。这一切都归结为改变实体设计,以免混淆注释。

谢谢瓦巴夫

于 2015-07-07T11:13:52.653 回答