From fca2516619e80e18a9f74de00e679cd4289dbcc0 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 21 Sep 2012 12:06:34 +0200 Subject: [PATCH] DATAJPA-257 - Make count query execution in SimpleJpaRepository more robust. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The execution of a count query can potentially return multiple values instead of just a single one. This causes persistence providers to throw an exception as we trigger ….getSingleResult() in SimpleJpaRepository. We're now calling …getResultList() and sum up all values returned. --- .../repository/query/JpaQueryExecution.java | 3 ++- .../data/jpa/repository/query/QueryUtils.java | 21 +++++++++++++++++++ .../support/SimpleJpaRepository.java | 3 ++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java index 953cf92e4..9d892d9e6 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java @@ -97,6 +97,7 @@ public abstract class JpaQueryExecution { // Execute query to compute total TypedQuery projection = repositoryQuery.createCountQuery(values); + List totals = projection.getResultList(); Long total = totals.size() == 1 ? totals.get(0) : totals.size(); @@ -160,4 +161,4 @@ public abstract class JpaQueryExecution { return result; } } -} \ No newline at end of file +} diff --git a/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java b/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java index b176250de..b883b37ef 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java @@ -27,6 +27,7 @@ import java.util.regex.Pattern; import javax.persistence.EntityManager; import javax.persistence.Parameter; import javax.persistence.Query; +import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.Expression; import javax.persistence.criteria.From; @@ -270,6 +271,26 @@ public abstract class QueryUtils { return orders; } + /** + * Executes a count query and transparently sums up all values returned. + * + * @param query must not be {@literal null}. + * @return + */ + public static Long executeCountQuery(TypedQuery query) { + + Assert.notNull(query); + + List totals = query.getResultList(); + Long total = 0L; + + for (Long element : totals) { + total += element == null ? 0 : element; + } + + return total; + } + /** * Creates a criteria API {@link javax.persistence.criteria.Order} from the given {@link Order}. * diff --git a/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java b/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java index 6dc74bddb..127291188 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java @@ -40,6 +40,7 @@ import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.query.QueryUtils; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; @@ -402,7 +403,7 @@ public class SimpleJpaRepository implements JpaRepos query.setFirstResult(pageable.getOffset()); query.setMaxResults(pageable.getPageSize()); - Long total = getCountQuery(spec).getSingleResult(); + Long total = QueryUtils.executeCountQuery(getCountQuery(spec)); List content = total > pageable.getOffset() ? query.getResultList() : Collections. emptyList(); return new PageImpl(content, pageable, total);