Jpa 如何计算子查询返回的行数?
我想这样做:Jpa 如何计算子查询返回的行数?,jpa,jpa-2.0,jpql,criteria-api,Jpa,Jpa 2.0,Jpql,Criteria Api,我想这样做: select count(*) from (select ...) 就像在SQL中一样,但是在JPA中 有什么想法吗?如果您想使用JPA标准API,这应该可以做到: CriteriaBuilder cb = getEntityManager().getCriteriaBuilder(); CriteriaQuery<Long> query = cb.createQuery(Long.class); Root<Entity> root = query.
select count(*) from (select ...)
就像在SQL中一样,但是在JPA中
有什么想法吗?如果您想使用JPA标准API,这应该可以做到:
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<Entity> root = query.from(Entity.class);
//Selecting the count
query.select(cb.count(root));
//Create your search criteria
Criteria criteria = ...
//Adding search criteria
query.where(criteria);
Long count = getEntityManager().createQuery(query).getSingleResult();
我也偶然发现了这个问题。我最终希望执行以下JPQL: 选择COUNTu 从…起 选择不同的u 来自用户u 加入u.r 其中r.id在1中 但这是不可能的,也不符合API标准。研究表明,这只是JPA中的一个设计限制。JPA规范规定,子查询仅在WHERE和HAVING子句中受支持,因此在FROM中不受支持 以以下JPQL格式重写查询: 选择COUNTu 来自用户u 你在哪里 选择不同的u 来自用户u 加入u.r 其中r.id在1中 使用JPA标准API,如下所示: CriteriaQuery=cb.createQueryLong.class; Root u=query.fromUser.class; Subquery Subquery=query.subqueryUser.class; Root u_u2;=subquery.fromUser.class; subquery.selectu_u.distincttrue.whereu_u.joinroles.getid.inArrays.asList1L; query.selectcb.countu.wherecb.inu.valuesubquery; 长计数=entityManager.createQueryquery.getSingleResult; // ...
为我解决了功能需求。这也将使您能够充分了解如何解决特定的功能需求。使用以下代码段来计算给定条件查询的行数:
public static Query createNativeCountQuery(EntityManager em, CriteriaQuery<?> criteriaQuery) {
org.hibernate.query.Query<?> hibernateQuery = em.createQuery(criteriaQuery).unwrap(org.hibernate.query.Query.class);
String hqlQuery = hibernateQuery.getQueryString();
QueryTranslatorFactory queryTranslatorFactory = new ASTQueryTranslatorFactory();
QueryTranslator queryTranslator = queryTranslatorFactory.createQueryTranslator(
hqlQuery,
hqlQuery,
Collections.emptyMap(),
em.getEntityManagerFactory().unwrap(SessionFactoryImplementor.class),
null
);
queryTranslator.compile(Collections.emptyMap(), false);
String sqlCountQueryTemplate = "select count(*) from (%s)";
String sqlCountQuery = String.format(sqlCountQueryTemplate, queryTranslator.getSQLString());
Query nativeCountQuery = em.createNativeQuery(sqlCountQuery);
Map<Integer, Object> positionalParamBindings = getPositionalParamBindingsFromNamedParams(hibernateQuery);
positionalParamBindings.forEach(nativeCountQuery::setParameter);
return nativeCountQuery;
}
private static Map<Integer, Object> getPositionalParamBindingsFromNamedParams(org.hibernate.query.Query<?> hibernateQuery) {
Map<Integer, Object> bindings = new HashMap<>();
for (var namedParam : hibernateQuery.getParameterMetadata().getNamedParameters()) {
for (int location : namedParam.getSourceLocations()) {
bindings.put(location + 1, hibernateQuery.getParameterValue(namedParam.getName()));
}
}
return bindings;
}
问题是我想要得到子查询返回行的计数。这似乎是不可能的,因为子查询不能像在JPAThis中那样使用,它根本不能回答具体的问题。OP询问的是如何计算子查询的结果,而不是如何计算查询的结果。如果返回的行数为零,则此操作不起作用。Hibernate使用javax.persistence.NoresultException进行崩溃如果您想计算聚合的结果,就不能使用这种方法query@Martin你建议用什么方法来区分计数和任意标准查询?@svlada,我没有找到有效的解决方案,只返回所有行并在应用程序服务器上对它们进行计数。@Martin在这种情况下,我认为唯一的选择是执行普通的JDBC查询。除了枚举和列表参数外,它还可以工作
public static Query createNativeCountQuery(EntityManager em, CriteriaQuery<?> criteriaQuery) {
org.hibernate.query.Query<?> hibernateQuery = em.createQuery(criteriaQuery).unwrap(org.hibernate.query.Query.class);
String hqlQuery = hibernateQuery.getQueryString();
QueryTranslatorFactory queryTranslatorFactory = new ASTQueryTranslatorFactory();
QueryTranslator queryTranslator = queryTranslatorFactory.createQueryTranslator(
hqlQuery,
hqlQuery,
Collections.emptyMap(),
em.getEntityManagerFactory().unwrap(SessionFactoryImplementor.class),
null
);
queryTranslator.compile(Collections.emptyMap(), false);
String sqlCountQueryTemplate = "select count(*) from (%s)";
String sqlCountQuery = String.format(sqlCountQueryTemplate, queryTranslator.getSQLString());
Query nativeCountQuery = em.createNativeQuery(sqlCountQuery);
Map<Integer, Object> positionalParamBindings = getPositionalParamBindingsFromNamedParams(hibernateQuery);
positionalParamBindings.forEach(nativeCountQuery::setParameter);
return nativeCountQuery;
}
private static Map<Integer, Object> getPositionalParamBindingsFromNamedParams(org.hibernate.query.Query<?> hibernateQuery) {
Map<Integer, Object> bindings = new HashMap<>();
for (var namedParam : hibernateQuery.getParameterMetadata().getNamedParameters()) {
for (int location : namedParam.getSourceLocations()) {
bindings.put(location + 1, hibernateQuery.getParameterValue(namedParam.getName()));
}
}
return bindings;
}