From 84314e279e2bc3bb9e87f7bcd5b186545083f3bd Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 28 Jun 2016 14:55:26 +0200 Subject: [PATCH] DATAJPA-920 - Add support for exists projection in repository query derivation. We now support exists projections in derived queries. Queries select the primary key using tuple queries limiting the result to the first row. interface UserRepository extends Repository { boolean existsByFirstname(String firstname); } Original pull request: #176. --- .../jpa/repository/query/JpaQueryCreator.java | 30 ++++++++++-- .../repository/query/JpaQueryExecution.java | 14 ++++++ .../repository/query/PartTreeJpaQuery.java | 14 +++++- .../sample/EmbeddedIdExampleEmployee.java | 13 ++++- .../sample/IdClassExampleDepartment.java | 3 ++ .../domain/sample/IdClassExampleEmployee.java | 16 ++++++- .../RepositoryWithCompositeKeyTests.java | 47 ++++++++++++++++++- .../jpa/repository/UserRepositoryTests.java | 12 +++++ .../PartTreeJpaQueryIntegrationTests.java | 31 ++++++++++++ .../EmployeeRepositoryWithEmbeddedId.java | 8 +++- .../sample/EmployeeRepositoryWithIdClass.java | 8 +++- .../jpa/repository/sample/UserRepository.java | 5 ++ 12 files changed, 192 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java index 9f808a3ad..e5c98830d 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2015 the original author or authors. + * Copyright 2008-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package org.springframework.data.jpa.repository.query; +import static org.springframework.data.jpa.domain.AbstractPersistable_.*; import static org.springframework.data.jpa.repository.query.QueryUtils.*; import static org.springframework.data.repository.query.parser.Part.Type.*; @@ -22,6 +23,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Set; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -31,6 +33,7 @@ import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.persistence.criteria.Selection; +import javax.persistence.metamodel.SingularAttribute; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.query.ParameterMetadataProvider.ParameterMetadata; @@ -46,6 +49,7 @@ import org.springframework.util.Assert; * Query creator to create a {@link CriteriaQuery} from a {@link PartTree}. * * @author Oliver Gierke + * @author Mark Paluch */ public class JpaQueryCreator extends AbstractQueryCreator, Predicate> { @@ -54,6 +58,7 @@ public class JpaQueryCreator extends AbstractQueryCreator query; private final ParameterMetadataProvider provider; private final ReturnedType returnedType; + private final PartTree tree; /** * Create a new {@link JpaQueryCreator}. @@ -67,6 +72,7 @@ public class JpaQueryCreator extends AbstractQueryCreator criteriaQuery = createCriteriaQuery(builder, type); @@ -88,7 +94,7 @@ public class JpaQueryCreator extends AbstractQueryCreator typeToRead = type.getTypeToRead(); - return typeToRead == null ? builder.createTupleQuery() : builder.createQuery(typeToRead); + return (typeToRead == null || tree.isExistsProjection()) ? builder.createTupleQuery() : builder.createQuery(typeToRead); } /** @@ -163,6 +169,24 @@ public class JpaQueryCreator extends AbstractQueryCreator id = root.getModel().getId(root.getModel().getIdType().getJavaType()); + query = query.multiselect(root.get((SingularAttribute) id).alias(id.getName())); + } else { + + List> selections = new ArrayList>(); + + Set> idClassAttributes = (Set>) root.getModel().getIdClassAttributes(); + + for (SingularAttribute attribute : idClassAttributes) { + selections.add(root.get((SingularAttribute) attribute).alias(attribute.getName())); + } + selections.add(root.get((SingularAttribute) id).alias(id.getName())); + query = query.multiselect(selections); + } } else { query = query.select((Root) root); } @@ -173,7 +197,7 @@ public class JpaQueryCreator extends AbstractQueryCreator[] parameterTypes = new Class[values.length]; @@ -173,6 +202,8 @@ public class PartTreeJpaQueryIntegrationTests { User findByIdAllIgnoringCase(Integer id); + boolean existsByFirstname(String firstname); + List findByCreatedAtAfter(@Temporal(TemporalType.TIMESTAMP) @Param("refDate") Date refDate); } } diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithEmbeddedId.java b/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithEmbeddedId.java index edf15484f..3454815fe 100644 --- a/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithEmbeddedId.java +++ b/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithEmbeddedId.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import com.querydsl.core.types.Predicate; * Demonstrates the support for composite primary keys with {@code @EmbeddedId}. * * @author Thomas Darimont + * @author Mark Paluch */ @Lazy public interface EmployeeRepositoryWithEmbeddedId @@ -37,4 +38,9 @@ public interface EmployeeRepositoryWithEmbeddedId QueryDslPredicateExecutor { List findAll(Predicate predicate, OrderSpecifier... orders); + + /** + * @see DATAJPA-920 + */ + boolean existsByName(String name); } diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithIdClass.java b/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithIdClass.java index f5439053e..a5228e523 100644 --- a/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithIdClass.java +++ b/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithIdClass.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,10 +30,16 @@ import com.querydsl.core.types.Predicate; * Demonstrates the support for composite primary keys with {@code @IdClass}. * * @author Thomas Darimont + * @author Mark Paluch */ @Lazy public interface EmployeeRepositoryWithIdClass extends JpaRepository, QueryDslPredicateExecutor { List findAll(Predicate predicate, OrderSpecifier... orders); + + /** + * @see DATAJPA-920 + */ + boolean existsByName(String name); } diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java index b01d19ee1..e9f7c2c5f 100644 --- a/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java +++ b/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java @@ -282,6 +282,11 @@ public interface UserRepository */ int countUsersByFirstname(String firstname); + /** + * @see DATAJPA-920 + */ + boolean existsByLastname(String lastname); + /** * @see DATAJPA-391 */