JPA,如何使用相同的 criteriaQuery 对象获取结果列表并进行 select 计数

JPA, How to use the same criteriaQuery Object to get a result List and to make a select count

我使用 criteriaBuilder 为特定类型创建 criteriaQuery。

CriteriaQuery<? extends File> criteriaQuery = criteriaBuilder.createQuery(Folder.class);

查询非常复杂,我必须添加多个连接等。

我在使用entityManager的createQuery方法时需要限制查询的结果

final TypedQuery<? extends File> query = this.entityManager.createQuery(criteriaQuery)
                .setFirstResult(start).setMaxResults(filePerPage);

但我还需要知道在没有限制的情况下我可以获得多少结果,因为我需要它来计算分页系统的页数。

所以我使用了另一个 criteriaQueryObject 来创建一个 select 计数

CriteriaQuery<Long> criteriaQueryCount = criteriaBuilder.createQuery(Long.class);

它有效,但我必须应用相同的联接和相同的过滤器,所以就像我做了两次一样。

例如:

//creation of the criteriaBuilders from specific types
CriteriaQuery<? extends File> criteriaQuery = criteriaBuilder.createQuery(Folder.class);

CriteriaQuery<Long> criteriaQueryCount = criteriaBuilder.createQuery(Long.class);

//creation of the roots
Root<? extends File> root = criteriaQuery.from(Folder.class),
                     rootCount = criteriaQuery.from(Folder.class);

//list of predicates feeded next
List<Predicate> criteriaList = new ArrayList<>(),
                criteriaCountList = new ArrayList<>();

//adding a join and the predicates
CriteriaBuilder.In<Long> inTagIds = criteriaBuilder.in(root.join("tags", JoinType.INNER).get("id"));
CriteriaBuilder.In<Long> inTagIdsCount = criteriaBuilder.in(rootCount.join("tags", JoinType.INNER).get("id"));

tags.forEach(t -> {
       inTagIds.value(t.getId());
       inTagIdsCount.value(t.getId());
});

criteriaList.add(inTagIds);
criteriaCountList.add(inTagIds);

.... I have almost 10 others filters like this one.

//generating the requests
criteriaQuery.where(criteriaBuilder.and(criteriaList.toArray(new Predicate[0])));

criteriaQuery.distinct(true);

criteriaQueryCount.select(criteriaBuilder.count(rootCount));

criteriaQueryCount.where(criteriaBuilder.and(criteriaCountList.toArray(new Predicate[0])));

final TypedQuery<? extends File> query = this.entityManager.createQuery(criteriaQuery)
                .setFirstResult(searchDto.start).setMaxResults(this.filePerPage);

Long count = this.entityManager.createQuery(criteriaQueryCount).getSingleResult();

List<? extends File> searchRs = query.getResultList();

我的问题是,有没有更方便的方法,我想使用相同的 CriteriaQuery 对象 and/or 相同的根,这可能吗?

在一种方法中做到这一点的唯一方法是让它使用未类型化的 CriteriaQuery(并抑制警告),并 return 使用未类型化的 TypedQuery。您可以传入一个布尔值,告诉它在进行计数查询时不要进行排序等。调用方法处理输入,也必须抑制警告。

希望有更优雅的方式,但仅此而已。它实际上在幕后将所有 criteriaquery 垃圾转换为 JPQL,因此在这种情况下,返回到巨大的字符串块几乎更好。