我编写了一个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的(看似晦涩的)功能非常适合我的目的。我发现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
某些JPA提供程序确实支持UNION,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#UNION
但是您的查询看起来非常复杂,并且不是面向对象的,因此使用本机SQL查询可能是最佳选择。