【问题标题】:Spring Data JPA Pagination (Pageable) with Dynamic Queries带有动态查询的 Spring Data JPA 分页(可分页)
【发布时间】:2013-10-31 15:06:54
【问题描述】:

我有一个简单的查询,如下“从用户中选择 *”。我还使用 Pageable 来启用分页。

此查询可能有基于给定参数是否为空的可选谓词。

例如,如果给出“code”参数且不为空,则查询变为 "select * from USERS where code = :code";

据我所知,我无法使用 @Query 注释来实现这一点。我可以实现自定义存储库并使用 EntityManager 创建动态查询。 但是,我不确定如何将“Pageable”与之集成以获取分页结果。

我怎样才能做到这一点?

【问题讨论】:

    标签: pagination spring-data-jpa


    【解决方案1】:

    在 Spring Data 中使用 QueryDSL(作为标准 API 的替代方案)很容易做到这一点。使用以下 QueryDSLPredicateExecutor 方法开箱即用地支持它,如果不应用任何限制,您可以将 null 作为 Predicate 传递:

    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 部分的 cmets 中讨论了您的场景。

    【讨论】:

    • 现在在使用 QueryDslRepositorySupport 时,您仍然可以访问此功能,因为它使用 #getQuerydsl() 公开了底层的 querydsl 实例
    【解决方案2】:

    获取 querydsl 查询的页面结果有点复杂,因为您需要两个查询:一个查询条目总数,另一个查询页面中您需要的条目列表。 您可以使用以下超类:

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

    【讨论】:

    • 但是 applyPagination 方法使用 JPQLQuery 对象
    • 这不会执行两次查询——一次获取结果,一次获取计数?那可不好。
    • @JoshM.:一般来说,这就是分页的工作方式。
    【解决方案3】:

    您必须使用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;
        ...
    }
    

    它有效,但如果在您的查询中获得了 fetch,那么您将收到此警告

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

    它会减慢您的请求因此解决方案是通过 fetch 并定义一个 @BatchSize(size=10) 并使用 Hibernate.initialize(....) 来获取集合和其他对象类型中的数据。

    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】:

      此处的信息已过时。让您的存储库实现QueryDslPredicateExecutor 并免费提供分页。

      【讨论】:

      • 您的链接似乎已过时
      猜你喜欢
      • 2014-12-11
      • 1970-01-01
      • 2013-09-15
      • 2023-03-10
      • 2020-07-05
      • 2017-05-04
      • 2021-02-24
      • 2016-12-01
      • 2019-03-12
      相关资源
      最近更新 更多