代码之家  ›  专栏  ›  技术社区  ›  Sean Patrick Floyd

在JPA2中,使用CriteriaQuery,如何计算结果

  •  97
  • Sean Patrick Floyd  · 技术社区  · 14 年前

    我对JPA2比较陌生,它是CriteriaBuilder/CriteriaQuery API:

    CriteriaQuery javadoc

    CriteriaQuery in the Java EE 6 tutorial

    我想计算CriteriaQuery的结果,而不实际检索它们。如果可能的话,我没有找到任何这样的方法,唯一的方法就是:

    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    
    CriteriaQuery<MyEntity> cq = cb
            .createQuery(MyEntityclass);
    
    // initialize predicates here
    
    return entityManager.createQuery(cq).getResultList().size();
    

    这不是正确的方法…

    有解决办法吗?

    6 回复  |  直到 6 年前
        1
  •  185
  •   dur    8 年前

    类型查询 MyEntity 就要回来了 实体 . 您需要查询 Long .

    CriteriaBuilder qb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Long> cq = qb.createQuery(Long.class);
    cq.select(qb.count(cq.from(MyEntity.class)));
    cq.where(/*your stuff*/);
    return entityManager.createQuery(cq).getSingleResult();
    

    显然,您将希望使用在示例中跳过的任何限制和分组等来构建表达式。

        2
  •  28
  •   reyiyo    13 年前

    我已经使用cb.createQuery()(不带result type参数)对其进行了排序:

    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();
        }
    }
    

    希望有帮助:)

        3
  •  22
  •   axtavt    14 年前
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Long> cq = cb.createQuery(Long.class);
    cq.select(cb.count(cq.from(MyEntity.class)));
    
    return em.createQuery(cq).getSingleResult();
    
        4
  •  8
  •   Community CDub    7 年前

    因为其他答案是正确的,但太简单了,所以为了完整性,我在下面介绍代码片段来执行 SELECT COUNT 在一 复杂的 JPA条件查询(具有多个联接、提取、条件)。

    它有点改动 this answer .

    public <T> long count(final CriteriaBuilder cb, final CriteriaQuery<T> selectQuery,
            Root<T> root) {
        CriteriaQuery<Long> query = createCountQuery(cb, selectQuery, root);
        return this.entityManager.createQuery(query).getSingleResult();
    }
    
    private <T> CriteriaQuery<Long> createCountQuery(final CriteriaBuilder cb,
            final CriteriaQuery<T> criteria, final Root<T> root) {
    
        final CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
        final Root<T> countRoot = countQuery.from(criteria.getResultType());
    
        doJoins(root.getJoins(), countRoot);
        doJoinsOnFetches(root.getFetches(), countRoot);
    
        countQuery.select(cb.count(countRoot));
        countQuery.where(criteria.getRestriction());
    
        countRoot.alias(root.getAlias());
    
        return countQuery.distinct(criteria.isDistinct());
    }
    
    @SuppressWarnings("unchecked")
    private void doJoinsOnFetches(Set<? extends Fetch<?, ?>> joins, Root<?> root) {
        doJoins((Set<? extends Join<?, ?>>) joins, root);
    }
    
    private void doJoins(Set<? extends Join<?, ?>> joins, Root<?> root) {
        for (Join<?, ?> join : joins) {
            Join<?, ?> joined = root.join(join.getAttribute().getName(), join.getJoinType());
            joined.alias(join.getAlias());
            doJoins(join.getJoins(), joined);
        }
    }
    
    private void doJoins(Set<? extends Join<?, ?>> joins, Join<?, ?> root) {
        for (Join<?, ?> join : joins) {
            Join<?, ?> joined = root.join(join.getAttribute().getName(), join.getJoinType());
            joined.alias(join.getAlias());
            doJoins(join.getJoins(), joined);
        }
    }
    

    希望能节省别人的时间。

    因为IMHOJPA标准API既不直观,也不可读。

        5
  •  2
  •   Guido Medina    6 年前

    这有点棘手,根据您使用的JPA 2实现,这一个适用于EclipseLink 2.4.1,但不适用于Hibernate,这里是EclipseLink的通用标准查询计数:

    public static Long count(final EntityManager em, final CriteriaQuery<?> criteria)
      {
        final CriteriaBuilder builder=em.getCriteriaBuilder();
        final CriteriaQuery<Long> countCriteria=builder.createQuery(Long.class);
        countCriteria.select(builder.count(criteria.getRoots().iterator().next()));
        final Predicate
                groupRestriction=criteria.getGroupRestriction(),
                fromRestriction=criteria.getRestriction();
        if(groupRestriction != null){
          countCriteria.having(groupRestriction);
        }
        if(fromRestriction != null){
          countCriteria.where(fromRestriction);
        }
        countCriteria.groupBy(criteria.getGroupList());
        countCriteria.distinct(criteria.isDistinct());
        return em.createQuery(countCriteria).getSingleResult();
      }
    

    前几天我从eclipselink迁移到hibernate,不得不将count函数改为下面的函数,所以请随意使用,因为这是一个很难解决的问题,可能对您的情况不起作用,它从hibernate 4.x开始就一直在使用,请注意,我不会尝试猜测哪个是根,而是从查询中传递它,这样问题就解决了。有太多模棱两可的角落案例需要尝试猜测:

      public static <T> long count(EntityManager em,Root<T> root,CriteriaQuery<T> criteria)
      {
        final CriteriaBuilder builder=em.getCriteriaBuilder();
        final CriteriaQuery<Long> countCriteria=builder.createQuery(Long.class);
    
        countCriteria.select(builder.count(root));
    
        for(Root<?> fromRoot : criteria.getRoots()){
          countCriteria.getRoots().add(fromRoot);
        }
    
        final Predicate whereRestriction=criteria.getRestriction();
        if(whereRestriction!=null){
          countCriteria.where(whereRestriction);
        }
    
        final Predicate groupRestriction=criteria.getGroupRestriction();
        if(groupRestriction!=null){
          countCriteria.having(groupRestriction);
        }
    
        countCriteria.groupBy(criteria.getGroupList());
        countCriteria.distinct(criteria.isDistinct());
        return em.createQuery(countCriteria).getSingleResult();
      }
    
        6
  •  1
  •   Pavel Evstigneev    8 年前

    您还可以使用投影:

    ProjectionList projection = Projections.projectionList();
    projection.add(Projections.rowCount());
    criteria.setProjection(projection);
    
    Long totalRows = (Long) criteria.list().get(0);