JPA 2.0:计算任意CriteriaQuery?

blu*_*ubb 11 orm jpa count criteria-api jpa-2.0

我正在尝试实现以下便捷方法:

/**
 * Counts the number of results of a search.
 * @param criteria The criteria for the query.
 * @return The number of results of the query.
 */
public int findCountByCriteria(CriteriaQuery<?> criteria);
Run Code Online (Sandbox Code Playgroud)

在Hibernate中,这是通过

criteria.setProjection(Projections.rowCount());
Run Code Online (Sandbox Code Playgroud)

JPA中的上述内容是什么?我找到了许多简单的计数示例,但没有一个使用了应该确定行数的CriteriaQuery.

编辑:

不幸的是我发现@Pascal的答案不正确.问题非常微妙,只有在使用连接时才显示:

// Same query, but readable:
// SELECT *
// FROM Brain b
// WHERE b.iq = 170

CriteriaQuery<Person> query = cb.createQuery(Person.class);
Root<Person> root = query.from(Person.class);
Join<Object, Object> brainJoin = root.join("brain");
Predicate iqPredicate = cb.equal(brainJoin.<Integer>get("iq"), 170);
query.select(root).where(iqPredicate);
Run Code Online (Sandbox Code Playgroud)

在调用时findCountByCriteria(query),它会因以下异常而死亡:

org.hibernate.hql.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.iq' [select count(generatedAlias0) from xxx.tests.person.dom.Person as generatedAlias0 where generatedAlias1.iq=170]
Run Code Online (Sandbox Code Playgroud)

还有其他方法可以提供这样的CountByCriteria方法吗?

Jos*_*tin 17

我写了一个实用程序类, JDAL JpaUtils来做它:

  • 计数结果: Long count = JpaUtils.count(em, criteriaQuery);
  • 复制CriteriaQueries: JpaUtils.copyCriteria(em, criteriaQueryFrom, criteriaQueryTo);
  • 得到计数标准: CriteriaQuery<Long> countCriteria = JpaUtils.countCriteria(em, criteria)

等等...

如果您对源代码感兴趣,请参阅JpaUtils.java


rey*_*iyo 5

我已经使用 cb.createQuery() (没有结果类型参数)对此进行了整理:

public class Blah() {

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery query = criteriaBuilder.createQuery();
    Root<Entity> root;
    Predicate whereClause;
    EntityManager entityManager;
    Class<Entity> domainClass;

    ... Methods to create where clause ...

    public Blah(EntityManager entityManager, Class<Entity> domainClass) {
        this.entityManager = entityManager;
        this.domainClass = domainClass;
        criteriaBuilder = entityManager.getCriteriaBuilder();
        query = criteriaBuilder.createQuery();
        whereClause = criteriaBuilder.equal(criteriaBuilder.literal(1), 1);
        root = query.from(domainClass);
    }

    public CriteriaQuery<Entity> getQuery() {
        query.select(root);
        query.where(whereClause);
        return query;
    }

    public CriteriaQuery<Long> getQueryForCount() {
        query.select(criteriaBuilder.count(root));
        query.where(whereClause);
        return query;
    }

    public List<Entity> list() {
        TypedQuery<Entity> q = this.entityManager.createQuery(this.getQuery());
        return q.getResultList();
    }

    public Long count() {
        TypedQuery<Long> q = this.entityManager.createQuery(this.getQueryForCount());
        return q.getSingleResult();
    }
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你 :)

我所做的是类似于 CriteriaBuilder 的构建器,您可以在其中构建查询并使用相同的条件限制调用 list() 或 count()