使用 JPA Criteria API 的 select 子句中的子查询

发布于 2024-10-11 05:05:35 字数 968 浏览 7 评论 0原文

正如标题所示,我正在尝试在 select 子句中插入一个子查询,就像这个简单的 SQL 一样:

SELECT id, name, (select count(*) from item) from item

这显然只是一个模拟查询,只是为了表明我的观点。 (重点是获取查询返回的每个项目的最后一张发票。)

我已经尝试过:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> c = cb.createTupleQuery();
Root<Item> item= c.from(Item.class);

Subquery<Long> scount = c.subquery(Long.class);
Root<Item> sarticolo = scount.from(Item.class);
scount.select(cb.count(sitem));

c.multiselect(item.get("id"),item.get("nome"), scount);

Query q = em.createQuery(c);
q.setMaxResults(100);
List<Tuple> result = q.getResultList();

for(Tuple t: result){
  System.out.println(t.get(0) + ", " + t.get(1) + ", " + t.get(2));
}

但我只得到:

java.lang.IllegalStateException: select子句中不能出现子查询

如何才能得到类似的结果?

I'm trying, as in title, to insert a subquery in select clause like in this simple SQL:

SELECT id, name, (select count(*) from item) from item

this is obviously only a mock query just to make my point. (The point would be to get the last invoice for each item returned by the query.)

I've tried this:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> c = cb.createTupleQuery();
Root<Item> item= c.from(Item.class);

Subquery<Long> scount = c.subquery(Long.class);
Root<Item> sarticolo = scount.from(Item.class);
scount.select(cb.count(sitem));

c.multiselect(item.get("id"),item.get("nome"), scount);

Query q = em.createQuery(c);
q.setMaxResults(100);
List<Tuple> result = q.getResultList();

for(Tuple t: result){
  System.out.println(t.get(0) + ", " + t.get(1) + ", " + t.get(2));
}

but I only get:

java.lang.IllegalStateException:
Subquery cannot occur in select clause

How can I get a similar result?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

白况 2024-10-18 05:05:35

JPA 2.1 和 Hibernate 5.0 支持它。您只需将 getSelection() 添加到主查询的 multiselect 中的子查询参数即可。

c.multiselect(item.get("id"),item.get("nome"), scount.getSelection());

看看这个工作示例:

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<NotificationInfo> cq = builder.createQuery(NotificationInfo.class); //wrapper class
Root<Notification> n = cq.from(Notification.class); //root entity

//Subquery
Subquery<Long> sqSent = cq.subquery(Long.class);
Root<NotificationUser> sqSentNU = sqSent.from(NotificationUser.class);
sqSent.select(builder.count(sqSentNU));
sqSent.where(
        builder.equal(sqSentNU.get(NotificationUser_.notification), n),  //join subquery with main query
        builder.isNotNull(sqSentNU.get(NotificationUser_.sendDate))
);

cq.select(
    builder.construct(
            NotificationInfo.class,
            n.get(Notification_.idNotification),
            n.get(Notification_.creationDate),
            n.get(Notification_.suspendedDate),
            n.get(Notification_.type),
            n.get(Notification_.title),
            n.get(Notification_.description),
            sqSent.getSelection()
    )
);
em.createQuery(cq).getResultList();

It is supported in JPA 2.1 and Hibernate 5.0. You just had to add getSelection() to the subquery argument in the multiselect of the main query.

c.multiselect(item.get("id"),item.get("nome"), scount.getSelection());

Take a look at this working example:

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<NotificationInfo> cq = builder.createQuery(NotificationInfo.class); //wrapper class
Root<Notification> n = cq.from(Notification.class); //root entity

//Subquery
Subquery<Long> sqSent = cq.subquery(Long.class);
Root<NotificationUser> sqSentNU = sqSent.from(NotificationUser.class);
sqSent.select(builder.count(sqSentNU));
sqSent.where(
        builder.equal(sqSentNU.get(NotificationUser_.notification), n),  //join subquery with main query
        builder.isNotNull(sqSentNU.get(NotificationUser_.sendDate))
);

cq.select(
    builder.construct(
            NotificationInfo.class,
            n.get(Notification_.idNotification),
            n.get(Notification_.creationDate),
            n.get(Notification_.suspendedDate),
            n.get(Notification_.type),
            n.get(Notification_.title),
            n.get(Notification_.description),
            sqSent.getSelection()
    )
);
em.createQuery(cq).getResultList();
白龙吟 2024-10-18 05:05:35

JPA 不支持 select 子句中的子查询。

您需要更改查询以便不在 select 子句中使用 require 子查询、执行多个查询或使用本机 SQL 查询。

JPA does not support sub-queries in the select clause.

You need to either change your query so as not to use require the sub-query in the select clause, execute multiple queries, or use a native SQL query.

心房敞 2024-10-18 05:05:35

您需要合并子查询结果:

Expression<ResultType> expression = criterioaBuilder.coalesce(subquery, criteriaBuilder.literal((ResultType) defaultResult);
query.select(expression);

You need to coalesce your subquery result:

Expression<ResultType> expression = criterioaBuilder.coalesce(subquery, criteriaBuilder.literal((ResultType) defaultResult);
query.select(expression);
且行且努力 2024-10-18 05:05:35

JPA 现在支持 select 子句中的子查询。

编辑:
JPA 2.1 JPQL BNF 支持 select 子句中的子查询,即使这不是必需的。据我所知 Eclipselink 也支持这个和 Hibernate(在 5.1 中测试)。

JPA now supports sub-queries in the select clause.

EDIT:
JPA 2.1 JPQL BNF supports sub-queries in select clause even if it's not required. As far as I know Eclipselink Supports this and Hibernate too (tested in 5.1).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文