3

我编写了一个 SQL 查询,它基本上从多个表中进行选择,以确定哪些表具有自特定日期以来创建的行。我的 SQL 看起来像这样:

SELECT widget_type FROM(
  SELECT 'A' as widget_type
  FROM widget_a
  WHERE creation_timestamp > :cutoff
  UNION
  SELECT 'B' as widget_type
  FROM widget_b
  WHERE creation_timestamp > :cutoff
) types
GROUP BY widget_type
HAVING count(*)>0

这在 SQL 中运行良好,但我最近发现,虽然 JPA 可能使用联合来执行“每类表”多态查询,但 JPQL 不支持查询中的联合。所以这让我想知道 JPA 是否有替代方案可以用来完成同样的事情。

实际上,我会查询十几个表,而不仅仅是两个,所以我想避免单独查询。出于可移植性的原因,我还想避免执行本机 SQL 查询。

在我上面链接的问题中,有人询问映射到 widget_a 和 widget_b 的实体是否属于同一继承树。是的,他们是。但是,如果我从他们的基类中选择,我不相信我会有办法为不同的子实体指定不同的字符串常量,对吗?如果我可以选择实体的类名而不是我提供的字符串,那也可能符合我的目的。但我也不知道这是否可能。想法?

4

2 回答 2

13

我进行了更多搜索,发现 JPA 的一个(看似晦涩难懂的)功能完美地满足了我的目的。我发现 JPA 2 有一个type关键字,允许您将多态查询限制为特定的子类,如下所示:

SELECT widget
FROM BaseWidget widget
WHERE TYPE(widget) in (WidgetB, WidgetC)

我发现 JPA(或至少作为 JPA 实现的 Hibernate)type不仅允许您在约束中使用,而且还允许在选择列表中使用。这大约是我的查询最终的样子:

SELECT DISTINCT TYPE(widget)
FROM BaseWidget widget
WHERE widget.creationTimestamp > :cutoff

该查询返回一个Class对象列表。我最初的查询是选择字符串文字,因为这最接近我在 SQL 中所做的。在我的情况下,选择Class实际上是更可取的。但是,如果我确实更喜欢根据实体的类型选择一个常量,那么这就是Oracle 文档用来说明case语句的确切场景:

SELECT p.name
CASE TYPE(p)
  WHEN Student THEN 'kid'
  WHEN Guardian THEN 'adult'
  WHEN Staff THEN 'adult'
  ELSE 'unknown'
END
FROM Person p
于 2013-03-05T06:45:45.910 回答
0

一些 JPA 提供者确实支持 UNION,

http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#UNION

但是您的查询似乎非常复杂,并且非面向对象,因此使用本机 SQL 查询可能是最好的。

于 2013-02-26T14:39:42.490 回答