ユーザーがこのエンティティの属性で複数の条件(eq、ne、gt、ltなど)を使用してそのエンティティを検索できるように、システムにエンティティの「高度な検索」機能を実装しています。 JPAのCriteria APIを使用してCriteriaクエリを動的に生成してから、setFirstResult()
&setMaxResults()
を使用してページネーションをサポートしています。この時点まではすべて順調でしたが、結果グリッドに結果の合計数を表示したいのですが、基準クエリの合計数を取得する簡単な方法がわかりませんでした。
これは私のコードがどのように見えるかです:
_CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Brand> cQuery = builder.createQuery(Brand.class);
Root<Brand> from = cQuery.from(Brand.class);
CriteriaQuery<Brand> select = cQuery.select(from);
.
.
//Created many predicates and added to **Predicate[] pArray**
.
.
select.where(pArray);
// Added orderBy clause
TypedQuery typedQuery = em.createQuery(select);
typedQuery.setFirstResult(startIndex);
typedQuery.setMaxResults(pageSize);
List resultList = typedQuery.getResultList();
_
私の結果セットは大きくなる可能性があるため、カウントクエリのためにエンティティをロードしたくないので、CriteriaのrowCount()
メソッドのような合計カウントを取得する効率的な方法を教えてください(HibernateのCriteriaにあると思います)。
おかげでウラジミール!私はあなたのアイデアを取り入れて、個別のカウントクエリを使用して、既存の述語の配列を使用しました。最終的な実装は次のようになります。
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Brand> cQuery = builder.createQuery(Brand.class);
Root<Brand> from = cQuery.from(Brand.class);
CriteriaQuery<Brand> select = cQuery.select(from);
.
.
//Created many predicates and added to **Predicate[] pArray**
.
.
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
cq.select(builder.count(cq.from(Brand.class)));
// Following line if commented causes [org.hibernate.hql.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.enabled' [select count(generatedAlias0) from xxx.yyy.zzz.Brand as generatedAlias0 where ( generatedAlias1.enabled=:param0 ) and ( lower(generatedAlias1.description) like :param1 )]]
em.createQuery(cq);
cq.where(pArray);
Long count = em.createQuery(cq).getSingleResult();
.
.
select.where(pArray);
.
.
// Added orderBy clause
TypedQuery typedQuery = em.createQuery(select);
typedQuery.setFirstResult(startIndex);
typedQuery.setMaxResults(pageSize);
List resultList = typedQuery.getResultList()
これはうまく機能していますが、それでもなぜ私は書く必要があるのか分かりません
em.createQuery(cq);
動作するようにします。何か案が?
カウントを使用しないのはなぜですか?
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Long> cQuery = builder.createQuery(Long.class);
Root<Brand> from = cQuery.from(Brand.class);
CriteriaQuery<Long> select = cQuery.select(builder.count(from));
.
.
//Created many predicates and added to **Predicate[] pArray**
.
.
select.where(pArray);
// Added orderBy clause
TypedQuery<Long> typedQuery = em.createQuery(select);
typedQuery.setFirstResult(startIndex);
//typedQuery.setMaxResults(pageSize);
// here is the size of your query
Long result = typedQuery.getSingleResult();
JPAプロバイダーとしてHibernateを使用している場合は、 projections 、特にProjections.rowCount()
をご覧ください。
ただし、クエリを2回実行する必要がある場合があります。最初にカウントを取得してから、結果を取得します。
プレーンJPAの場合、他のアプローチが必要になる場合があることに注意してください。
両方の答えが機能すると思います。しかし、それらのいずれも最適ではありません。 ThinkFloyd
の問題は、createQuery
が2回使用されることです。そしてVladimir Ivanov
はCriteriaQuery
の2つのインスタンスを作成しましたが、これらは不要だと思います。
val cb = entityManager.criteriaBuilder
val cq = cb.createQuery(ManualQuery::class.Java)
val manualQuery = cq.from(ManualQuery::class.Java)
val predicates = ArrayList<Predicate>()
/*
predications.....
*/
cq.select(manualQuery)
.where(*predicates.toTypedArray())
.orderBy(cb.desc(manualQuery.get<ZonedDateTime>("createdDate")))
val query = entityManager.createQuery(cq)
// total rows count
val count = query.resultList.size
val indexedQuery = query
.setFirstResult((currentPage - 1) * pageSize)
.setMaxResults(itemsPerPage)
うまくいく。そして、それはKotlinで行われます。 Javaで同じ方法で行います。