我发布此问题+答案作为How to perform a non-polymorphic HQL query in Hibernate?的扩展。它还强调了Hibernate 4.1.x和4.3.5之间的行为变化,以及如果您的映射在非严格需要时包含@DiscriminatorColumn
的错误。
我有一个具体的超类,患者,有一个具体的子类,截肢者。每个人都有自己的表('患者'截肢者'),Hibernate继承策略是JOINED。
首先,根据JPA规范,我选择了@DiscriminatorColumn
区分截肢者与主要patient
表中的香草患者,使用' P'对于香草患者和' A'截肢者:
@Entity
@Table(name="patient")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="type", discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue("P")
public class Patient {...
和
@Entity
@Table(name="amputee")
@DiscriminatorValue("A")
public class Amputee extends Patient {...
选择所有患者的JPQL查询,包括香草和截肢者(工作正常):
select p from Patient p
JPQL查询只选择截肢者,而不是香草(工作正常):
select a from Amputee a
JPQL查询仅使用TYPE运算符选择vanilla(非 -amputee)患者:
select p from Patient p where type(p) <> Amputee
...适用于Hibernate 4.1.3,但不适用于4.3.5(这些只是我测试过的两个版本,也可能是其他版本)。
4.1.3已经生成了一些时髦的连接和切换/案例SQL,但至少有效。 4.3.5生成无效的SQL ,至少在使用上述映射时。这里生成的WHERE子句带有错误条件:
where case when patient0_1_.id is not null then A when patient0_.id is not null then 'P' end<>'A'
你可以看到&#34;然后A&#34; bit应该在单引号中有A,但不是,所以SQL失败。我在Hibernate日志中通过一个模糊的警告引出了解决方案:
WARN HHH000457: Joined inheritance hierarchy [cellnostics.model.Patient] defined explicit @DiscriminatorColumn. Legacy Hibernate behavior was to ignore the @DiscriminatorColumn. However, as part of issue HHH-6911 we now apply the explicit @DiscriminatorColumn. If you would prefer the legacy behavior, enable the hibernate.discriminator.ignore_explicit_for_joined setting (hibernate.discriminator.ignore_explicit_for_joined=true)
事实证明,对于SINGLE_TABLE或JOINED层次结构,Hibernate不需要@DiscriminatorColumn
:它会在所有相关表中发出体操连接+案例语句。但是,如果您遵循JPA建议并且执行在此类映射中指定@DiscriminatorColumn
,则Hibernate会在4.3.5版中生成无效SQL ,同时生成笨重但至少在4.1.3中使用SQL。
您可以在Hibernate JIRA: HHH-6911上了解有关@DiscriminatorColumn
问题的更多信息。
因此,解决方案是没有@DiscriminatorColumn
s的映射:
@Entity
@Table(name="patient")
@Inheritance(strategy=InheritanceType.JOINED)
public class Patient {...
和
@Entity
@Table(name="amputee")
public class Amputee extends Patient {...
...对于原始的非多态查询:
select p from Patient p where type(p) <> Amputee
生成正确的SQL并返回正确的结果:
where case when patient0_1_.id is not null then 1 when patient0_.id is not null then 0 end<>1