关于@ ForceDiscriminator / @ DiscriminatorOptions(force = true)的使用

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

当我一次又一次地运行时,我认为可能有助于澄清:首先,在使用JOINED_TABLE映射时,Hibernate确实不需要区分。 但是,使用SINGLE_TABLE时确实需要它。 更重要的是,其他JPA提供商大多都需要它。

Hibernate在执行多态JOINED_TABLE查询时实际上做的是使用case-switch创建一个名为clazz的鉴别器,该case-switch在外部连接inheritance树中涉及的所有表之后检查是否存在对于具体子类唯一的字段。 在persistence.xml包含"hibernate.show_sql"属性时,您可以清楚地看到这一点。 在我看来,这可能是JOINED_TABLE查询的完美解决方案,所以Hibernate人员吹嘘它是正确的。

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

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

@ForceDiscriminator@DiscriminatorOptions(force=true)肯定有助于缓解一点痛苦,但您必须在创建第一个实体之前使用它们,或者强制使用SQL语句手动添加缺少的鉴别器值。 如果您敢于远离Hibernate,那么至少需要花费一些代码来删除这些Hibernate特定的注释,从而产生对迁移的阻力。 这显然是Hibernate在这种情况下所关心的。

根据我的经验,供应商锁定是每个市场领导者最疯狂梦想的天堂,因为它是马基雅维利亚魔术棒,可以毫不费力地保护市场份额; 因此,只要客户不反击并强制给予高于收益的供应商的价格,就会这样做。 谁说开源世界会有什么不同?

ps,只是为了避免任何混淆:我与任何JPA实现者无关。

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

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

 select * from TABLE where YOUR PREDICATE AND DiscriminatorColumn = DiscriminatorValue 

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

例如,我有一个Person实体,其中包含名称,出生日期等内容。此实体可以由其他几个实体(如EmployeeCustomer 。 当我不引用其他实体的Person ,而是引用EmployeeCustomer ,不使用鉴别​​器,因为Hibernate被指示提取任何一个。

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

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

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

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

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

谢谢Vaibhav