【问题标题】:How to execute a JPAQuery with pagination using Spring Data and QueryDSL如何使用 Spring Data 和 QueryDSL 执行带有分页的 JPAQuery
【发布时间】:2014-09-12 21:04:36
【问题描述】:

我有这个请求与queryDSL 合作得很好:

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

但是如果我们将它与spring data jpa 一起使用,它的等价物是什么

ao_respository.findAll(Predicate arg0, Pageable arg1);

因为我想返回一个Page 并且只使用querydsl 它不会实现Page 没有spring data jpa

我尝试将我的 where 放入 Predicate arg0 但我遇到了这个异常

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

其中lot 被声明为QLot lot = QLot.lot;

【问题讨论】:

  • 我也在寻找答案。如何将您的问题改写为“如何使用 Spring Data 和 QueryDSL 执行带有分页的 JPAQuery”……我知道您有标签,但标题无助于获得答案。
  • 我更新了标题 ;)
  • 我提出了一个解决方案,但最后有一个警告

标签: spring hibernate spring-data spring-data-jpa querydsl


【解决方案1】:

如果您在 querydsl 中有一个有效的、复杂的查询,并且您想使用 springdata 分页,您必须:

  1. 让您的 querydsl/repository 方法返回 Page&lt;T&gt;

     Page<YourEntity> yourSelect(Pageable aPageable)
    
  2. 使用 querydsl offsetlimit 来分页您的结果集

    List<YourEntity>  theResultList = jpaQueryFactory
                    .select(<whatever complext jpaquery you like>)
                    .offset(aPageable.getOffset())
                    .limit(aPageable.getPageSize())
                    .fetch();                                                          
    
  3. 提供一个LongSuplier,计算与您的查询相关的所有可用结果,并使用PageableExecutionUtils 将结果返回为Page

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

【讨论】:

  • 如果有例子参考就好了
【解决方案2】:

返回一个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);

我创建了这个函数来获取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);
}

【讨论】:

    【解决方案3】:

    我创建了自己的 Page 类并执行如下查询:

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

    我的页面类:

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

    它有效,但我收到了这个警告

    十一月2014 年 2 月 21 日上午 6 点 48 分 54 秒 org.hibernate.hql.internal.ast.QueryTranslatorImpl 列表警告: HHH000104:使用集合获取指定的 firstResult/maxResults; 在内存中申请!

    【讨论】:

    • 当你加入 fetch 时,不能在 SQL 级别应用属性分页。
    • 是的,但没有替代方法可以避免此警告?因为我需要你使用 fetch 在我的页面上显示数据。
    • 如果您摆脱左连接提取并为集合成员使用例如批量提取,则可以避免此警告。
    猜你喜欢
    • 2016-10-21
    • 2018-12-22
    • 2020-06-05
    • 2016-11-15
    • 2012-07-25
    • 2012-11-09
    • 2020-01-12
    • 2016-03-28
    • 2016-01-11
    相关资源
    最近更新 更多