JPQL等同于使用联合并选择常量的SQL查询

问题描述 投票:3回答:2

我编写了一个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 does not support unions。因此,我想知道JPA是否可以替代我来完成同一件事。

实际上,我将针对十几个表进行查询,而不仅仅是两个表,因此我希望避免执行单独的查询。由于可移植性的原因,我也想避免执行本机SQL查询。

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

jpa jpql
2个回答
12
投票

我做了更多的搜索,发现JPA的(看似晦涩的)功能非常适合我的目的。我发现JPA 2有一个type关键字,它允许您将多态查询限制为特定的子类,例如:

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

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

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

该查询返回Class对象的列表。我最初的查询是选择字符串文字,因为这与我在SQL中所做的最接近。在我的情况下,实际上选择Class是可取的。但是,如果我确实希望根据实体的类型选择一个常量,那么这就是Oracle's documentation用于说明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

0
投票

某些JPA提供程序确实支持UNION,

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

但是您的查询看起来非常复杂,并且不是面向对象的,因此使用本机SQL查询可能是最佳选择。

© www.soinside.com 2019 - 2024. All rights reserved.