spring-data-jpa JPA条件api -分页中具体查询的记录总数

dwthyt8l  于 2022-11-10  发布在  Spring
关注(0)|答案(1)|浏览(219)

我在我的存储库层中编写分页函数。函数作为参数接收spring的可分页对象和一些值,如下所示:

public Page<Foo> filterFoo(Pageable pageable, String value) {
   CriteriaBuilder cb = entityManager.getCriteriaBuilder();
   CriteriaQuery<Foo> fooQuery = cb.createQuery(Foo.class);
   Root<Foo> foo = fooQuery .from(Foo.class);
   fooQuery .where(adding predicate for match value);

   List<Foo> result = entityManager.createQuery(fooQuery )
      .setFirstResult((pageable.getPageNumber() - 1) * pageable.getPageSize())
      .setMaxResults(pageable.getPageSize())
      .getResultList();
   return new PageImpl<>(result, pageable, xxxx);
}

函数返回了用我的结果填充的spring的PageImpl对象。对于PageImpl,我还需要设置符合 predicate 的对象的总数。当然,这个计数必须不包括maxResult和firstResult。是否可以用我的fooQuery创建另一个数据库调用,以获得该查询的总数据库记录数而不受限制?在JPA中使用可分页和条件API的最佳实践是什么?谢谢你的建议。

esyap4oy

esyap4oy1#

由于生成的SQL使用别名-您可能需要进行单独的查询以获取总行数。例如:

CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
countQuery.select(cb.count(countQuery.from(Foo.class)));
if (Objects.nonNull(filters)) {
    countQuery.where(filters);
}
return new PageImpl<>(result, pageable, em.createQuery(countQuery).getSingleResult());

其中,filters等于adding predicate for match value表达式。
此外,您可以使用带有自定义SQL函数的TupleQuery来计算一个select查询中的行数。如下所示:

public class SqlFunctionsMetadataBuilderContributor implements MetadataBuilderContributor {
    @Override
    public void contribute(MetadataBuilder metadataBuilder) {
        metadataBuilder.applySqlFunction(
            "count_over",
            new SQLFunctionTemplate(
                StandardBasicTypes.LONG,
                "(count(?1) over())"
            )
        );
    }
}

和条件:

public Page<Foo> findAll(Specification<Foo> specification, Pageable pageable) {
    CriteriaQuery<Tuple> cq = cb.createTupleQuery();
    Root<Foo.class> fooRoot = cq.from(Foo.class);
    cq.select(cb.tuple(fooRoot, cb.function("count_over", Long.class, fooRoot.get("id"))));

    Predicate filters = specification.toPredicate(fooRoot, cq, cb);
    if (Objects.nonNull(filters)) {
        cq.where(filters);
    }

    TypedQuery<Tuple> query = em.createQuery(cq);
    query.setFirstResult((int) pageable.getOffset());
    query.setMaxResults(pageable.getPageSize());
    List<Tuple> result = query.getResultList();
    if (result.isEmpty()) {
        return new PageImpl<>(List.of());
    }
    return new PageImpl<>(
        result.stream().map(tuple -> (Foo) tuple.get(0)).collect(toUnmodifiableList()),
        pageable,
        (long) result.get(0).get(1)
    );
}

了解有关SQLFunction的更多信息:https://vladmihalcea.com/hibernate-sql-function-jpql-criteria-api-query/Custom SQL for Order in JPA Criteria API的函数

相关问题