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,因此在这种情况下,返回到巨大的字符串块几乎更好。
我使用 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,因此在这种情况下,返回到巨大的字符串块几乎更好。