web-dev-qa-db-ja.com

動的クエリを使用したSpring Data JPAページネーション(ページング可能)

次のような「select * from USERS」という簡単なクエリがあります。また、Pageableを使用してページ分割を有効にします。

このクエリには、指定されたパラメーターがnullかどうかに基づいて、オプションの述語が含まれる場合があります。

たとえば、「code」パラメータが指定されていてnullでない場合、クエリは「select * from USERS where code =:code」になります。

私の知る限り、@ Queryアノテーションを使用してこれを実装することはできません。カスタムリポジトリを実装し、EntityManagerを使用して動的クエリを作成できます。ただし、ページング可能な結果を​​取得するために「Pageable」をそれとどのように統合できるかわかりません。

どうすればこれを達成できますか?

16
led

これは、(基準APIの代替として)QueryDSLを使用してSpring Dataで行うのが非常に簡単です。次のQueryDSLPredicateExecutorのメソッドですぐにサポートされます。制限を適用しない場合は、Predicateとしてnullを渡すことができます。

Page<T> findAll(com.mysema.query.types.Predicate predicate,
                Pageable pageable)

QueryDSLの使用はオプションではないかもしれませんが、以下の一連のチュートリアルを見ると、いくつかのアイデアが得られるかもしれません。

http://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-nine-conclusions/

あなたが持っているシナリオは、彼のガイドのパート9へのコメントで著者によって実際に議論されています。

15
Alan Hay

Querydslクエリのページ結果の取得は、2つのクエリが必要なので、やや複雑です。1つはエントリの総数、もう1つはページに必要なエントリのリストです。次のスーパークラスを使用できます。

public class QueryDslSupport<E, Q extends EntityPathBase<E>> extends QueryDslRepositorySupport {

  public QueryDslSupport(Class<E> clazz) {
    super(clazz);
  }

  protected Page<E> readPage(JPAQuery query, Q qEntity, Pageable pageable) {
    if (pageable == null) {
      return readPage(query, qEntity, new QPageRequest(0, Integer.MAX_VALUE));
    }
    long total = query.clone(super.getEntityManager()).count(); // need to clone to have a second query, otherwise all items would be in the list
    JPQLQuery pagedQuery = getQuerydsl().applyPagination(pageable, query);
    List<E> content = total > pageable.getOffset() ? pagedQuery.list(qEntity) : Collections.<E> emptyList();
    return new PageImpl<>(content, pageable, total);
  }

}
4
Sebastian

たとえば、querydslを使用してwhereを構築する必要があります。

_BooleanBuilder where = new BooleanBuilder();
...
    if(code  != null){
        where.and(YOURENTITY.code.eq(code));
    } 
_

そしてクエリを実行した後

_    JPAQuery query = new JPAQuery(entityManager).from(..)               
            .leftJoin( .. )
            ...
            .where(where)
_

自分のページを使う

_    MaPage<YOURENTITY> page = new MaPage<YOURENTITY>();
    page.number = pageNumber+1;

    page.content = query.offset(pageNumber*pageSize).limit(pageSize).list(...);

    page.totalResult = query.count();
_

私はそのようにMyPageを作成します

_public class MaPage<T> {

    public List<T> content;
    public int number;
    public Long totalResult;
    public Long totalPages;
    ...
}
_

動作しますが、クエリでフェッチを取得すると、この警告が表示されます

11月21、2014 6:48:54 AM org.hibernate.hql.internal.ast.QueryTranslatorImplリスト
警告:HHH000104:コレクションフェッチで指定されたfirstResult/maxResults。メモリに適用します!

そして、それはあなたの要求を遅くしますだから解決策は、フェッチを取得して@BatchSize(size=10)を定義し、Hibernate.initialize(....)を使用してコレクションや他のオブジェクトタイプのデータをフェッチすることです。

@ BatchSizeを設定して遅延初期化例外を回避するために関連エンティティからのデータを表示します

Spring DataとQueryDSLを使用してページネーションでJPAQueryを実行する方法

1
Youssef

ここの情報は時代遅れです。リポジトリに QueryDslPredicateExecutor を実装させると、ページングは​​無料で利用できます。

0
Steve Edgar