JPAページネーション
1. 概要
この記事では、pagination in the Java Persistence APIを実装する方法について説明します。
基本的なJQLとよりタイプセーフなCriteriaベースのAPIを使用してページングを行う方法を説明し、各実装の利点と既知の問題について説明します。
参考文献:
Spring RESTおよびAngularJSテーブルのページネーション
Springのページネーションを使用して簡単なAPIを実装する方法と、AngularJSとUI Gridでそれを使用する方法について詳細に説明します。
Spring Data JPA @Query
Spring Data JPAで@Queryアノテーションを使用して、JPQLとネイティブSQLを使用してカスタムクエリを定義する方法を学びます。
2. JQLとsetFirstResult()、setMaxResults()APIによるページ付け
ページネーションを実装する最も簡単な方法は、the Java Query Languageを使用することです–クエリを作成し、setMaxResults **およびsetFirstResultを介して構成します。
Query query = entityManager.createQuery("From Foo");
int pageNumber = 1;
int pageSize = 10;
query.setFirstResult((pageNumber-1) * pageSize);
query.setMaxResults(pageSize);
List fooList = query.getResultList();
APIは簡単です。
-
*setFirstResult(int*):ページネーションを開始するための結果セットのオフセット位置を設定します
-
setMaxResults(int):ページに含める必要のあるエンティティの最大数を設定します
2.1. 総数と最後のページ
より完全なページネーションソリューションを得るには、the total result countも取得する必要があります。
Query queryTotal = entityManager.createQuery
("Select count(f.id) from Foo f");
long countResult = (long)queryTotal.getSingleResult();
the last pageの計算も非常に便利です。
int pageSize = 10;
int pageNumber = (int) ((countResult / pageSize) + 1);
結果セットの合計カウントを取得するこのアプローチでは、追加のクエリ(カウント)が必要になることに注意してください。
3. エンティティのIDを使用したJQLによるページ付け
単純な代替のページ付け戦略は、first retrieve the full idsを実行し、次に–これらに基づいて–retrieve the full entitiesを実行することです。 これにより、エンティティのフェッチをより適切に制御できますが、IDを取得するにはテーブル全体をロードする必要があることも意味します。
Query queryForIds = entityManager.createQuery(
"Select f.id from Foo f order by f.lastName");
List fooIds = queryForIds.getResultList();
Query query = entityManager.createQuery(
"Select f from Foo e where f.id in :ids");
query.setParameter("ids", fooIds.subList(0,10));
List fooList = query.getResultList();
最後に、完全な結果を取得するには2つの異なるクエリが必要です。
4. Criteria APIを使用したJPAによるページ付け
次に、leverage the JPA Criteria APIでページネーションを実装する方法を見てみましょう。
int pageSize = 10;
CriteriaBuilder criteriaBuilder = entityManager
.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder
.createQuery(Foo.class);
Root from = criteriaQuery.from(Foo.class);
CriteriaQuery select = criteriaQuery.select(from);
TypedQuery typedQuery = entityManager.createQuery(select);
typedQuery.setFirstResult(0);
typedQuery.setMaxResults(pageSize);
List fooList = typedQuery.getResultList();
これは、目的が動的で失敗に対して安全なクエリを作成することである場合に役立ちます。 「ハードコードされた」、「文字列ベースの」JQLまたはHQLクエリとは対照的に、JPA Criteriaは、コンパイラがクエリエラーを動的にチェックするため、実行時のエラーを減らします。
JPA基準getting the total number of entitiesが十分に単純な場合:
CriteriaQuery countQuery = criteriaBuilder
.createQuery(Long.class);
countQuery.select(criteriaBuilder.count(
countQuery.from(Foo.class)));
Long count = entityManager.createQuery(countQuery)
.getSingleResult();
最終結果は、JPA Criteria APIを使用したa full pagination solutionです。
int pageNumber = 1;
int pageSize = 10;
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery countQuery = criteriaBuilder
.createQuery(Long.class);
countQuery.select(criteriaBuilder
.count(countQuery.from(Foo.class)));
Long count = entityManager.createQuery(countQuery)
.getSingleResult();
CriteriaQuery criteriaQuery = criteriaBuilder
.createQuery(Foo.class);
Root from = criteriaQuery.from(Foo.class);
CriteriaQuery select = criteriaQuery.select(from);
TypedQuery typedQuery = entityManager.createQuery(select);
while (pageNumber < count.intValue()) {
typedQuery.setFirstResult(pageNumber - 1);
typedQuery.setMaxResults(pageSize);
System.out.println("Current page: " + typedQuery.getResultList());
pageNumber += pageSize;
}
5. 結論
この記事では、JPAで利用できる基本的なページ付けオプションについて説明しました。
主にクエリのパフォーマンスに関連する欠点があるものもありますが、これらは通常、制御の向上と全体的な柔軟性によって相殺されます。
このSpringJPAチュートリアルの実装はthe GitHub projectにあります。これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。