提问者:小点点

JPA标准api-分页内具体查询的总记录


我正在为我的存储库层中的分页编程函数。函数接收作为参数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,我还需要设置适合谓词的对象的总计数。这个计数号当然必须没有maxResult和firstResult。是否可以使用我的foQuery创建另一个数据库调用来无限制地获取该查询的总数据库记录?在JPA中使用可分页和标准api的最佳实践是什么?谢谢您的建议。


共1个答案

匿名用户

因为生成的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());

其中过滤器等于您的为匹配值表达式添加谓词。

此外,您可以使用带有自定义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/和自定义SQL在JPA标准API