JPA 标准:在所有列的完整结果之前获取总数;重用 Where 子句
JPA Criteria: Obtain total count just before full result with all columns; reuse Where clause
在 JPA Criteria 中,我有一个复杂的有效查询。它涉及许多 Join 和一个复杂的 Where 子句。但就在我 运行 完整 selection 之前,我需要快速 COUNT
完整结果集。
我尝试使用 cb.count
重用我的 where
子句和我的顶级元素 nvRoot
中的所有连接和 select。但是我收到错误 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'
最简单的解决方法是将谓词构建部分提取到方法中并像这样重用它:
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();
其中 buildQuery
的定义如下:
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;
}
根的别名是在查询之间以某种随机方式生成的,所以让我们对它们进行硬编码。
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Result> criteriaQuery = cb.createQuery(Result.class);
Root<NvisionTrainee> nvRoot = criteriaQuery.from(Nv.class);
// -- root alias --
nvRoot.alias("nvRoot");
Join<Object,Object> plans = nvRoot.join("plans", JoinType.LEFT);
// -- root alias --
plans.alias("plansRoot");
// etc., other Joins
Predicate where = cb.conjunction();
// Complex Where clause built...
criteriaQuery.where(where);
CriteriaQuery<Long> cqCount = cb.createQuery(Long.class);
// -- Added additional roots with the same alias names --
Root<NvisionTrainee> nvRootCqCount = cqCount.from(Nv.class);
nvRootCqCount.alias("nvRoot");
Join<Object,Object> plansCqCount = nvRootCqCount.join("plans", JoinType.LEFT);
plansCqCount.alias("plansRoot");
// etc., other Joins
cqCount.select(cb.count(nvRootCqCount));
cqCount.distinct(true);
// -- and here 'where' substituted with 'criteriaQuery.getRestriction()' --
cqCount.where(criteriaQuery.getRestriction());
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();
手写的,所以我不确定这是否有效。我遇到过类似的错误问题:Invalid path: 'generatedAlias2.id'
.
在 JPA Criteria 中,我有一个复杂的有效查询。它涉及许多 Join 和一个复杂的 Where 子句。但就在我 运行 完整 selection 之前,我需要快速 COUNT
完整结果集。
我尝试使用 cb.count
重用我的 where
子句和我的顶级元素 nvRoot
中的所有连接和 select。但是我收到错误 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'
最简单的解决方法是将谓词构建部分提取到方法中并像这样重用它:
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();
其中 buildQuery
的定义如下:
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;
}
根的别名是在查询之间以某种随机方式生成的,所以让我们对它们进行硬编码。
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Result> criteriaQuery = cb.createQuery(Result.class);
Root<NvisionTrainee> nvRoot = criteriaQuery.from(Nv.class);
// -- root alias --
nvRoot.alias("nvRoot");
Join<Object,Object> plans = nvRoot.join("plans", JoinType.LEFT);
// -- root alias --
plans.alias("plansRoot");
// etc., other Joins
Predicate where = cb.conjunction();
// Complex Where clause built...
criteriaQuery.where(where);
CriteriaQuery<Long> cqCount = cb.createQuery(Long.class);
// -- Added additional roots with the same alias names --
Root<NvisionTrainee> nvRootCqCount = cqCount.from(Nv.class);
nvRootCqCount.alias("nvRoot");
Join<Object,Object> plansCqCount = nvRootCqCount.join("plans", JoinType.LEFT);
plansCqCount.alias("plansRoot");
// etc., other Joins
cqCount.select(cb.count(nvRootCqCount));
cqCount.distinct(true);
// -- and here 'where' substituted with 'criteriaQuery.getRestriction()' --
cqCount.where(criteriaQuery.getRestriction());
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();
手写的,所以我不确定这是否有效。我遇到过类似的错误问题:Invalid path: 'generatedAlias2.id'
.