0

JPA 标准中,我有一个有效的复杂查询。它涉及许多连接和一个复杂的 Where 子句。但就在我运行它以进行完整选择之前,我需要快速COUNT了解完整的结果集。

我试图重用我的where子句和我的所有联接,并从我的顶部元素中选择nvRoot,使用cb.count. 但我得到了错误Caused by: java.lang.IllegalStateException: No criteria query roots were specified

     CriteriaBuilder cb = entityManager.getCriteriaBuilder();
     CriteriaQuery<Result> criteriaQuery = cb.createQuery(Result.class);
     Root<NvisionTrainee> nvRoot = criteriaQuery.from(Nv.class);
     Join<Object,Object> plans = nvRoot.join("plans", JoinType.LEFT);
     // etc., other Joins

     Predicate where = cb.conjunction();
     // Complex Where clause built...
     criteriaQuery.where(where);

     // --- HERE I NEED TO RUN A QUICK COUNT QUERY, with all Joins/Where as built
     // --- BUT THE BELOW DOESN'T WORK: 
     // --- Caused by: java.lang.IllegalStateException: No criteria query roots were specified
     CriteriaQuery<Long> cqCount = cb.createQuery(Long.class);
     cqCount.select(cb.count(nvRoot));     
     cqCount.distinct(true);
     cqCount.where(where);
     Long totalCount = entityManager.createQuery(cqCount).getSingleResult();

     // --- THIS FULL QUERY WORKS (THE REMAINDER), IT GETS ME MY FULL SELECTION
     CompoundSelection<Result> selectionFull = cb.construct(
                                   Result.class,
                                   nvRoot.get("firstName"),
                                   // etc. - many columns
                                   );
     criteriaQuery.select(selectionFull);
     criteriaQuery.distinct(true);
     TypedQuery<Result> query = entityManager.createQuery(criteriaQuery);
     List<Result> results = query.getResultList();

根据下面的评论,我尝试添加cqCount.from(Nv.class)代码,但这给了我:

Invalid path: 'generatedAlias2.id'

4

1 回答 1

2

最简单的解决方法是将谓词构建部分提取到一个方法中并像这样重用它:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();

//count query
CriteriaQuery<Long> cqCount = cb.createQuery(Long.class);
Root<NvisionTrainee> nvCountRoot = buildQuery(cqCount, ...);
cqCount.select(cb.count(nvCountRoot));     
cqCount.distinct(true);
Long totalCount = entityManager.createQuery(cqCount).getSingleResult();

//actual query
CriteriaQuery<Result> criteriaQuery = cb.createQuery(Result.class);
Root<NvisionTrainee> nvRoot = buildQuery(criteriaQuery, ...); //you might need to return other paths created inside buildQuery if you need to use them in the SELECT clause
CompoundSelection<Result> selectionFull = cb.construct(
    Result.class,
    nvRoot.get("firstName"),
    ...
    );
criteriaQuery.select(selectionFull);
criteriaQuery.distinct(true);
TypedQuery<Result> query = entityManager.createQuery(criteriaQuery);
List<Result> results = query.getResultList();

wherebuildQuery定义如下:

private Root<NvisionTrainee> buildQuery(CriteriaQuery<?> query, ... /* possibly many other arguments*/) {
    Root<NvisionTrainee> nvRoot = query.from(Nv.class);
    Join<Object,Object> plans = nvRoot.join("plans", JoinType.LEFT);
    // etc., other Joins - build your WHERE clause here
    return nvRoot;
}
于 2020-07-26T17:40:34.487 回答