如何在 Hibernate 中执行非多态 HQL 查询?

Posted

技术标签:

【中文标题】如何在 Hibernate 中执行非多态 HQL 查询?【英文标题】:How to perform a non-polymorphic HQL query in Hibernate? 【发布时间】:2010-01-19 11:20:57 【问题描述】:

我使用的是 Hibernate 3.1.1,特别是,我使用的是 HQL 查询。

根据documentation,Hibernate 的查询是多态的:

类似from Cat as cat 的查询不仅返回Cat 的实例,还返回DomesticCat 等子类的实例。

如何查询 Cat 的实例,而不是它的任何子类?

我希望能够做到这一点,而不必明确提及每个子类。

我知道以下选项,但不满意:

    在查询后手动过滤实例,或者: 在鉴别器列上手动添加 WHERE 子句。

Hibernate 允许用户决定查询是否应该是多态的是有意义的,但我找不到这样的选项。

提前致谢!

【问题讨论】:

【参考方案1】:

在class mapping 中使用polymorphism="explicit"。这将导致查询只返回命名类的实例,而不是它的子类。

隐式多态意味着 该类的实例将是 由命名任何的查询返回 超类或实现的接口或 类,以及任何的实例 类的子类将被返回 通过命名类的查询 本身。显式多态性意味着 该类实例将被返回 仅通过明确命名的查询 那个班级。

【讨论】:

太棒了!在我的情况下,我需要它基于每个查询,而不是每个实体,但我认为我看到了一种方法 - 通过覆盖我的 EntityPersister 上的 isExplicitPolymorphism 方法。你当然给了我一个正确的方向。【参考方案2】:
SELECT cat FROM Cat cat WHERE cat.class='cat'

其中'cat' 的值是Cat 类的鉴别器值。

如果你使用TABLE_PER_CLASS,那么试试cat.class='Cat')(类名)

完全不是鉴别器列上的 where 子句,因为这样的查询将失败(鉴别器列仅在本机查询中可用)。

【讨论】:

谢谢,但我试图避免编辑 WHERE 子句。如果我同意你的建议,Hibernate 会将它自己的部分添加到 WHERE,它最终会变成“WHERE c.class='cat' AND c.class IN ('cat', 'domesticCat')”。我宁愿有办法告诉 Query 一次“关闭”它的多态能力(如果存在这样的事情)。 为什么不指定where子句? 因为我有一段通用的框架代码,可以对不同的实体执行不同的查询。我希望能够将配置参数传递给通用代​​码,以在多态和非多态模式之间切换。如果必须,通用代码修改 where 子句,但这需要查找鉴别器值(尽管并不难),并且可能会导致 where 子句中不必要的部分 (见我之前的评论)。【参考方案3】:

JPA 2 (Hibernate 3.5) 添加了对非多态查询的支持,这与 Hibernates .class 属性非常相似(正如 Bozho 上面回答的那样),但它不是 Hibernate 特定的。这是使用 TYPE 运算符完成的。如

Select b from Book b where TYPE(b) = Book

您可以在我的博客中阅读有关here 的更多信息

艾尔

【讨论】:

我最近从 Hibernate 4.1.3 升级到了 Java 8 所需的 4.3.5。我的非多态查询现在被破坏了:Hibernate 生成的 SQL 是错误的。在 4.1.3 中,它已经在 where 子句中做了一些时髦的 switch/case,但现在它是不正确的:鉴别器列值(一个字符串)是 notquoted: "...where case when当 Patient0_.id 不为 null 时,如果 Patient0_1_.id 不为空,则为 A,则为 'P' end'A'......”在“then A”中,它忽略了引用A,从而产生了无效的SQL。 查看我对此问题的扩展:***.com/questions/24512975/… 可能缺少“=”运算符。试试:TYPE(b) = Book【参考方案4】:

ORM 模仿 Java 模型:如果一个对象是另一种类型的实例(如果 PersianCat 的一个实例也是 Cat 的一个实例),那么对 Cat 的任何查询都必须是多态的(假设您查询一个 List 并询问如果条目匹配instanceof Cat

即使 Bozho 的解决方案也有些不纯,因为“类”列对您的休眠映射来说是不透明的,尽管我承认这是一个很好的折衷方案。您可以通过类的简单名称简单地获取鉴别器。

如果您感到舒适并且正在使用每个类的表,您始终可以对 Cat 表进行本机查询以获取 id,然后通过休眠获取条目.

【讨论】:

你是对的,99% 的情况下你应该像对待基类的任何其他实例一样对待子类的实例——就像在 Java 中使用 x instanceof Cat 一样。但是,我的问题是关于另外 1% 的情况,当您出于某种原因不想加载子类型时——就像在 Java 中使用 x.getClass() == Cat.class 一样。就我而言,它是在系统引导期间,当时我还不能实例化子类型对象。 你能分享你的设计吗?通常情况下,当事情变得如此困难时,设计可能会有缺陷或更好的做事方式。【参考方案5】:

看BaseQueryReturnFieldsCalculatorGC;它动态地向“where”添加一个条件,该条件仅选择 where class=XXX;您可以将此逻辑复制到 HQLQueryTemplate 并让用户定义“isNonPolymorphic”。

请注意,它仅适用于按层次结构的表,因为只有这样隐式类列才存在并且是可选择的。

【讨论】:

以上是关于如何在 Hibernate 中执行非多态 HQL 查询?的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate查询(HQL——Hibernate Query Language)

类型:。net;问题:HQL;结果:HQL: Hibernate查询语言

Hibernate之HQL查询的一些例子

Hibernate之HQL基本用法

Hibernate 之强大的HQL查询

具有具体类特定属性条件的多态 HQL 查询;可以吗?