16

我想做这样的事情:

select count(*) from (select ...)

(就像在 SQL 中一样),但在 JPA 中。

关于我将如何做的任何想法?

4

3 回答 3

32

我也偶然发现了这个问题。我最终想执行以下 JPQL:

SELECT COUNT(u)
FROM (
   SELECT DISTINCT u
   FROM User u
   JOIN u.roles r
   WHERE r.id IN (1)
)

但这是不可能的,也不能使用标准 API。研究表明,这只是 JPA 中的一个设计限制。JPA 规范声明子查询仅在WHEREandHAVING子句中受支持(因此不在FROM)中。

用以下 JPQL 形式重写查询:

SELECT COUNT(u)
FROM User u
WHERE u IN (
   SELECT DISTINCT u
   FROM User u
   JOIN u.roles r
   WHERE r.id IN (1)
)

使用 JPA Criteria API,如下所示:

CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<User> u = query.from(User.class);
Subquery<User> subquery = query.subquery(User.class);
Root<User> u_ = subquery.from(User.class);
subquery.select(u_).distinct(true).where(u_.join("roles").get("id").in(Arrays.asList(1L)));
query.select(cb.count(u)).where(cb.in(u).value(subquery));
Long count = entityManager.createQuery(query).getSingleResult();
// ...

已经解决了我的功能需求。这也应该让您有足够的洞察力来解决您的特定功能需求。

于 2012-08-22T15:32:26.050 回答
7

这应该可以解决问题(如果您想使用 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();

另一方面,如果你想使用 JP-QL,下面的代码应该可以解决问题:

//Add the where condition to the end of the query
Query query = getEntityManager().createQuery("select count(*) from Entity entity where...")
Long count = query.getSingleResult();
于 2011-03-26T16:10:47.503 回答
1

使用以下代码段计算给定条件查询的行数:

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;
}
于 2021-02-22T21:14:01.230 回答