Hayi
Hayi

Reputation: 6266

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

I have this request working good with queryDSL :

 Iterable<AO> query_result = new JPAQuery(entityManager).from(ao)
            .leftJoin( ao.lots , lot )
            .leftJoin( ao.acs , ac )
              .where(where).distinct()
                .list(ao);

But what is its equivalent if we use it with spring data jpa

ao_respository.findAll(Predicate arg0, Pageable arg1);

Because i want to return a Page and just with querydsl it doesn't implement Page without spring data jpa.

I try to put my where in Predicate arg0 but i got this exception

Undeclared path 'lot '. Add this path as a source to the query to be able to reference it

where lot is declared as QLot lot = QLot.lot;

Upvotes: 4

Views: 10240

Answers (3)

Stefan H&#252;ttemann
Stefan H&#252;ttemann

Reputation: 222

If you have a working, complex query in querydsl and you want to use springdata pagination, you have to:

  1. make your querydsl/repository method return Page<T>

     Page<YourEntity> yourSelect(Pageable aPageable)
    
  2. use querydsl offset and limit to page your result set

    List<YourEntity>  theResultList = jpaQueryFactory
                    .select(<whatever complext jpaquery you like>)
                    .offset(aPageable.getOffset())
                    .limit(aPageable.getPageSize())
                    .fetch();                                                          
    
  3. provide a LongSuplier counting all available results with respect to your query and use PageableExecutionUtils to return the result as Page

    final long theCount = jpaQueryFactory
          .selectFrom(<your select to count all results>)
          .fetchCount();
    
    return PageableExecutionUtils.getPage(theResultList, aPageable, () -> theCount);
    

Upvotes: 1

anat0lius
anat0lius

Reputation: 2275

Returning a Page:

JPAQuery query = 
    ...
    .orderBy(getOrderSpecifiers(pageable, MyEntity.class))
    .limit(pageable.getPageSize())
    .offset(pageable.getOffset());

long total = query.fetchCount();
List<MyEntity> content = query.fetch();
return new PageImpl<>(content, pageable, total);

And I created this function to get OrderSpecifier:

private OrderSpecifier[] getOrderSpecifiers(@NotNull Pageable pageable, @NotNull Class klass) {

    // orderVariable must match the variable of FROM
    String className = klass.getSimpleName();
    final String orderVariable = String.valueOf(Character.toLowerCase(className.charAt(0))).concat(className.substring(1));

    return pageable.getSort().stream()
            .map(order -> new OrderSpecifier(
                    Order.valueOf(order.getDirection().toString()),
                    new PathBuilder(klass, orderVariable).get(order.getProperty()))
            )
            .toArray(OrderSpecifier[]::new);
}

Upvotes: 7

Hayi
Hayi

Reputation: 6266

I created my own Page class and executed the query like this:

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




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

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

    page.totalResult = query.count();

My Page class:

public class MaPage<T> {

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

It works but I got 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!

Upvotes: 5

Related Questions