Spring Data JPA Pagination (Pageable) with Dynamic Queries

笑着哭i 提交于 2020-12-29 05:16:04

问题


I have a simple query as follows "select * from USERS". I also use Pageable to enable pagination.

This query may have optional predicates based on the given parameters being null or not.

For example if "code" parameter is given and not null, then the query becomes "select * from USERS where code = :code";

As far as I know I cannot implement this using @Query annotation. I can implement a custom repository and use EntityManager to create a dynamic query. However, I am not sure how I can integrate "Pageable" with that to get back paginated results.

How can I achieve this?


回答1:


This is very easy to do in Spring Data using QueryDSL (as alternative to the criteria API). It is supported out of the box with the following method of QueryDSLPredicateExecutor where you can just pass null as the Predicate if no restrictions are to be applied:

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

Using QueryDSL may not be an option for you however if you look at the following series of tutorials you might get some ideas.

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

The scenario you have is actually discussed by the author in the comments to part 9 of his guide.




回答2:


Getting page results for querydsl queries is somehow complicated since you need two queries: one for the total number of entries, and one for the list of entries you need in the page. You could use the following superclass:

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);
  }

}



回答3:


You have to use querydsl and build your where depending on not null parameter for example

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

and after execute the query

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

and use your own page

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

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

    page.totalResult = query.count();

I create MyPage like that

public class MaPage<T> {

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

it works but if in your query you got a fetch then you gonna have this warning

nov. 21, 2014 6:48:54 AM org.hibernate.hql.internal.ast.QueryTranslatorImpl list
WARN: HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!

and it will slow down your request So the solution is to get ride of the fetch and define a @BatchSize(size=10) and use Hibernate.initialize(....) to fetch data in collections and other object type.

Display data from related entities to avoid the lazy initialization exception with setting up @BatchSize

How to execute a JPAQuery with pagination using Spring Data and QueryDSL




回答4:


The information here is obsolete. Have your Repository implement the QueryDslPredicateExecutor and paging comes for free.



来源:https://stackoverflow.com/questions/19710079/spring-data-jpa-pagination-pageable-with-dynamic-queries

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!