type query java jpa-2.0 criteriaquery

java - type - En JPA 2, usando un CriteriaQuery, cómo contar resultados



jpa count query return type (7)

Como las demás respuestas son correctas, pero demasiado simples, para completar, presento el siguiente fragmento de código para realizar SELECT COUNT en una consulta sofisticada de Criterios JPA (con varias combinaciones, captaciones, condiciones).

Se modifica ligeramente esta respuesta .

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

Espero que le ahorre tiempo a alguien.

Porque la API de criterios JPA de IMHO no es intuitiva ni bastante legible.

Soy bastante nuevo en JPA 2 y es API de CriteriaBuilder / CriteriaQuery:

CriteriaQuery javadoc

CriteriaQuery en el tutorial de Java EE 6

Me gustaría contar los resultados de un CriteriaQuery sin realmente recuperarlos. Es posible, no encontré ningún método así, la única forma sería hacer esto:

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

Y esa no puede ser la forma correcta de hacerlo ...

¿Hay una solución?


Es un poco complicado, dependiendo de la implementación de JPA 2 que utilice, esta funciona para EclipseLink 2.4.1, pero no para Hibernate, aquí un conteo de CriteriaQuery genérico para 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(); }


Lo resolví usando cb.createQuery () (sin el parámetro de tipo de resultado):

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

Espero eso ayude :)


También puedes usar Proyecciones:

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


Una consulta de tipo MyEntity va a devolver MyEntity . Desea una consulta por un 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();

Obviamente, querrás construir tu expresión con las restricciones y agrupaciones, etc. que omitiste en el ejemplo.


Use countDistinct lugar de count .


CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Long> cq = cb.createQuery(Long.class); cq.select(cb.count(cq.from(MyEntity.class))); return em.createQuery(cq).getSingleResult();