タイトルのように、次の単純なSQLのようにselect句にサブクエリを挿入しようとしています。
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句で発生させることはできません
どうすれば同様の結果を得ることができますか?
JPA2.1およびHibernate5.0でサポートされています。メインクエリのmultiselect
のサブクエリ引数にgetSelection()
を追加する必要がありました。
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();
JPAは、select句のサブクエリをサポートしていません。
Select句でrequiresub-queryを使用しないようにクエリを変更するか、複数のクエリを実行するか、ネイティブSQLクエリを使用する必要があります。
サブクエリの結果を合体させる必要があります。
Expression<ResultType> expression = criterioaBuilder.coalesce(subquery, criteriaBuilder.literal((ResultType) defaultResult);
query.select(expression);
JPAは、select句でサブクエリをサポートするようになりました。
編集:
JPA 2.1 JPQL BNFは、必須ではない場合でも、select句でサブクエリをサポートします。私の知る限り、EclipselinkはこれとHibernateもサポートしています(5.1でテスト済み)。