【发布时间】:2020-06-18 10:10:43
【问题描述】:
我想使用相同的Predicate 数组运行一对查询:一个用于计算记录,一个用于获取某一页的记录。对我来说,这似乎是一个非常正常的用例,所以一定有一个好的方法可以做到这一点,但我还没有找到它。
所以这是获取实体的部分:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
EntityType<ENTITY> entityType = entityManager.getMetamodel().entity(FooEntity.class);
CriteriaQuery<FooEntity> entityQuery = criteriaBuilder.createQuery(FooEntity.class);
Root<FooEntity> entityRoot = entityQuery.from(FooEntity.class);
// Use the criteria builder, root, and type to create some predicates.
Predicate[] predicates = createPredicates(criteriaBuilder, entityRoot, entityType );
// Fetch the entities.
entityQuery.select(entityRoot);
entityQuery.where(predicates);
List<FooEntity> entities = entityManager.createQuery(entityQuery)
.setFirstResult(0) // Just get the first page
.setMaxResults(50)
.getResultList();
这行得通。我们得到了我们想要的,谓词是正确的等等。
但是,使用相同谓词创建另一个查询来确定计数会失败。我尝试了两种不同的方法:
(1) 重用Root:
CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class);
countQuery.select(criteriaBuilder.count(entityRoot));
countQuery.where(predicates);
long count = entityManager.createQuery(countQuery).getSingleResult();
这不起作用并给我java.lang.IllegalStateException: No criteria query roots were specified。奇怪,因为我明确指定了Root,但也许我不能重新使用从不同的CriteriaQuery 创建的Root?好的,让我们从同一个CriteriaQuery创建一个...
(2) 创建一个新的Root:
CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class);
countQuery.select(criteriaBuilder.count(countQuery.from(FooEntity.class));
countQuery.where(predicates);
long count = entityManager.createQuery(countQuery).getSingleResult();
现在我们得到一个不同的错误:org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.fooProperty' [select count(generatedAlias0) from com.foo.FooEntity as generatedAlias0 where ( generatedAlias1.fooProperty = :param0 )]
查看创建的 HQL,“from”子句似乎设置了 generatedAlias0,但“where”子句中的所有内容都引用了 generatedAlias1。我的猜测是因为Predicate 的数组是使用与CriteriaQuery<Long> 不同的Root 构建的。
那么,如果这两种方法都不起作用,我将如何重新使用相同的 Predicate 数组?我真的必须用第二个Root 重新创建所有这些吗?这对我来说似乎太过分了,特别是因为他们都是Root<FooEntity>。我觉得一定有更好的方法。
【问题讨论】:
-
像你一样指定root
ntityQuery.from(FooEntity.class); -
我不明白你的评论。我的选项 (1) 是一样的,但只是为了后代,我尝试从实体查询创建一个新根:
countQuery.select(criteriaBuilder.count(entityQuery.from(FooEntity.class)));...但正如预期的那样,它产生了相同的错误(“未指定条件查询根” )。
标签: java hibernate jpa criteria-api