JPA + Hibernate count(*) using CriteriaBuilder - with generatedAlias

走远了吗. 提交于 2019-12-04 12:08:00

Your code fails because you are using different Root instances for the count and the where clauses: the first one (in order of definition) generates generatedAlias1 alias, and the other generates generatedAlias0. You need to refactor the code in order to use the same Root instance in both places:

CriteriaQuery<Long> cqCount = builder.createQuery(Long.class);
Root<ReqStatCumulative> entityRoot = cqCount.from(cqEntity.getResultType());
cqCount.select(builder.count(entityRoot));
Path<Long> processTimeSeconds = entityRoot.get("processTimeSeconds");
cqCount.where(qb.and(qb.greaterThan(processTimeSeconds, (long) cfg.getProcessTimeExceedsSec()),//
                qb.lessThan(processTimeSeconds, (long) cfg.getProcessTimeExceedsSec() + 100))//
                );//    
return em.createQuery(cqCount).getSingleResult();

I had the same problem, and I solved with:

CriteriaQuery<Long> countCriteria = cb.createQuery(Long.class);
Root<EntityA> countRoot = countCriteria.from(cq.getResultType());
Set<Join<EntityA, ?>> joins = originalEntityRoot.getJoins();
for (Join<EntityA, ?> join :  joins) {
    countRoot.join(join.getAttribute().getName());
}
countCriteria.select(cb.count(countRoot));
if(finalPredicate != null)
    countCriteria.where(finalPredicate);

TypedQuery<Long> queryCount = entityManager.createQuery(countCriteria);
Long count = queryCount.getSingleResult();

Where

originalEntityRoot is the main root where I did the query with the where clauses.

I was looking a more generic solution based on the OP's question. And just leaving a more generic solution based on @Hector's example:

public class CountQueryHelper<T> {

    final Class<T> typeParameterClass;

    public CountQueryHelper(Class<T> typeParameterClass) {
        this.typeParameterClass = typeParameterClass;
    }

    public CriteriaQuery<Long> getCountQuery(CriteriaQuery<T> originalQuery, EntityManager em) {
        CriteriaBuilder cb = em.getCriteriaBuilder();

        // create count query
        CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);


        // start copying root/joins/restrictions from  the original query

        // copy roots
        for (Root r : originalQuery.getRoots()) {
            Root root = countQuery.from(r.getModel());
            root.alias(r.getAlias());
        }

        // copy joins
        for (Root r : originalQuery.getRoots()) {
            Set<Join<T, ?>> joins = r.getJoins();
            for (Join<T, ?> join : joins) {
                for (Root countRoot : countQuery.getRoots()) {
                    try {
                        Join joinOnCount = countRoot.join(join.getAttribute().getName());
                        joinRecursive(joinOnCount, join);
                    } catch (IllegalArgumentException e) {
                        // attribute does not exist on this root
                    }
                }
            }
        }

        countQuery.select(cb.count(countQuery.from(this.typeParameterClass)));

        //  copy restrictions
        if (originalQuery.getRestriction() != null) {
            countQuery.where(originalQuery.getRestriction());
        }

        return countQuery;
    }

    private void joinRecursive(Join countJoins, Join<T, ?> originalJoin) {
        for(Join original : originalJoin.getJoins()) {
            Join<Object, Object> childJoin = countJoins.join(original.getAttribute().getName());
            joinRecursive(childJoin, original);
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!