带有JPA Criteria API的select子句中的子查询

时间:2011-01-11 20:33:56

标签: jpa select subquery criteria

我正在尝试在标题中在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子句

我怎样才能得到类似的结果?

4 个答案:

答案 0 :(得分:16)

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();

答案 1 :(得分:7)

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

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

答案 2 :(得分:4)

您需要合并子查询结果:

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

答案 3 :(得分:3)

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

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