Подзапрос в предложении select с API JPA Criteria - PullRequest
15 голосов
/ 11 января 2011

Я пытаюсь, как в заголовке, вставить подзапрос в предложении 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 ]

17 голосов
/ 15 сентября 2016

Поддерживается в 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();
7 голосов
/ 12 января 2011

JPA не поддерживает подзапросы в предложении select.

Вам необходимо либо изменить запрос, чтобы не использовать требование подзапроса в предложении select, выполнить несколько запросов или использовать собственный запрос SQL.

4 голосов
/ 20 мая 2017

Вам необходимо объединить свой результат подзапроса:

Expression<ResultType> expression = criterioaBuilder.coalesce(subquery, criteriaBuilder.literal((ResultType) defaultResult);
query.select(expression);
3 голосов
/ 11 января 2016

JPA теперь поддерживает подзапросы в предложении select.

EDIT:
JPA 2.1 JPQL BNF поддерживает подзапросы в предложении select, даже если это не требуется. Насколько я знаю, Eclipselink поддерживает это и Hibernate (протестировано в 5.1).

...