From 3062cb1aa195fa8b40cf87d16f8810232cd4a4d2 Mon Sep 17 00:00:00 2001 From: Nikita Mishchenko Date: Sun, 6 Nov 2016 01:28:19 +0100 Subject: [PATCH] Delete by Predicate feature --- .../repository/support/DeleteQuerydsl.java | 43 ++++++++++++++ .../support/QueryDslJpaRepository.java | 59 +++++++++++++++---- .../support/QueryDslJpaRepositoryTests.java | 17 ++++++ 3 files changed, 108 insertions(+), 11 deletions(-) create mode 100644 src/main/java/org/springframework/data/jpa/repository/support/DeleteQuerydsl.java diff --git a/src/main/java/org/springframework/data/jpa/repository/support/DeleteQuerydsl.java b/src/main/java/org/springframework/data/jpa/repository/support/DeleteQuerydsl.java new file mode 100644 index 0000000000..ffb18e5edd --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/support/DeleteQuerydsl.java @@ -0,0 +1,43 @@ +package org.springframework.data.jpa.repository.support; + +import com.querydsl.core.types.EntityPath; +import com.querydsl.jpa.EclipseLinkTemplates; +import com.querydsl.jpa.HQLTemplates; +import com.querydsl.jpa.OpenJPATemplates; +import com.querydsl.jpa.impl.JPADeleteClause; +import org.springframework.data.jpa.provider.PersistenceProvider; + +import javax.persistence.EntityManager; + +/** + * Helper instance to ease access to DeleteClause JPA query API. + * + * @author Nikita Mishchenko + */ +public class DeleteQuerydsl { + + private final EntityManager em; + private final PersistenceProvider provider; + private final EntityPath path; + + public DeleteQuerydsl(EntityManager em, EntityPath path) { + this.em = em; + this.provider = PersistenceProvider.fromEntityManager(em); + this.path = path; + } + + public JPADeleteClause createQuery() { + switch (provider) { + case ECLIPSELINK: + return new JPADeleteClause(em, path, EclipseLinkTemplates.DEFAULT); + case HIBERNATE: + return new JPADeleteClause(em, path, HQLTemplates.DEFAULT); + case OPEN_JPA: + return new JPADeleteClause(em, path, OpenJPATemplates.DEFAULT); + case GENERIC_JPA: + default: + return new JPADeleteClause(em, path); + } + } + +} diff --git a/src/main/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepository.java b/src/main/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepository.java index c1a59fb7a7..85e37a61b0 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepository.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepository.java @@ -28,6 +28,7 @@ import org.springframework.data.querydsl.EntityPathResolver; import org.springframework.data.querydsl.QSort; import org.springframework.data.querydsl.QueryDslPredicateExecutor; +import org.springframework.data.querydsl.QueryDslPredicateModifyingExecutor; import org.springframework.data.querydsl.SimpleEntityPathResolver; import org.springframework.data.repository.support.PageableExecutionUtils; import org.springframework.data.repository.support.PageableExecutionUtils.TotalSupplier; @@ -38,29 +39,32 @@ import com.querydsl.core.types.dsl.PathBuilder; import com.querydsl.jpa.JPQLQuery; import com.querydsl.jpa.impl.AbstractJPAQuery; +import com.querydsl.jpa.impl.JPADeleteClause; +import org.springframework.transaction.annotation.Transactional; /** * QueryDsl specific extension of {@link SimpleJpaRepository} which adds implementation for * {@link QueryDslPredicateExecutor}. - * + * * @author Oliver Gierke * @author Thomas Darimont * @author Mark Paluch * @author Jocelyn Ntakpe */ public class QueryDslJpaRepository extends SimpleJpaRepository - implements QueryDslPredicateExecutor { + implements QueryDslPredicateExecutor, QueryDslPredicateModifyingExecutor { private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE; private final EntityPath path; private final PathBuilder builder; private final Querydsl querydsl; + private final DeleteQuerydsl deleteQuerydsl; /** * Creates a new {@link QueryDslJpaRepository} from the given domain class and {@link EntityManager}. This will use * the {@link SimpleEntityPathResolver} to translate the given domain class into an {@link EntityPath}. - * + * * @param entityInformation must not be {@literal null}. * @param entityManager must not be {@literal null}. */ @@ -71,7 +75,7 @@ public QueryDslJpaRepository(JpaEntityInformation entityInformation, Enti /** * Creates a new {@link QueryDslJpaRepository} from the given domain class and {@link EntityManager} and uses the * given {@link EntityPathResolver} to translate the domain class into an {@link EntityPath}. - * + * * @param entityInformation must not be {@literal null}. * @param entityManager must not be {@literal null}. * @param resolver must not be {@literal null}. @@ -84,6 +88,7 @@ public QueryDslJpaRepository(JpaEntityInformation entityInformation, Enti this.path = resolver.createPath(entityInformation.getJavaType()); this.builder = new PathBuilder(path.getType(), path.getMetadata()); this.querydsl = new Querydsl(entityManager, builder); + this.deleteQuerydsl = new DeleteQuerydsl(entityManager, path); } /* @@ -113,7 +118,7 @@ public List findAll(Predicate predicate, OrderSpecifier... orders) { return executeSorted(createQuery(predicate).select(path), orders); } - /* + /* * (non-Javadoc) * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.Predicate, org.springframework.data.domain.Sort) */ @@ -122,7 +127,7 @@ public List findAll(Predicate predicate, Sort sort) { return executeSorted(createQuery(predicate).select(path), sort); } - /* + /* * (non-Javadoc) * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.mysema.query.types.OrderSpecifier[]) */ @@ -150,6 +155,16 @@ public long get() { }); } + /* + * (non-Javadoc) + * @see org.springframework.data.querydsl.QueryDslPredicateModifyingExecutor#delete(com.mysema.query.types.Predicate) + */ + @Transactional + @Override + public long delete(Predicate... predicate) { + return createDeleteClause(predicate).execute(); + } + /* * (non-Javadoc) * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#count(com.mysema.query.types.Predicate) @@ -159,7 +174,7 @@ public long count(Predicate predicate) { return createQuery(predicate).fetchCount(); } - /* + /* * (non-Javadoc) * @see org.springframework.data.querydsl.QueryDslPredicateExecutor#exists(com.mysema.query.types.Predicate) */ @@ -170,7 +185,7 @@ public boolean exists(Predicate predicate) { /** * Creates a new {@link JPQLQuery} for the given {@link Predicate}. - * + * * @param predicate * @return the Querydsl {@link JPQLQuery}. */ @@ -193,7 +208,29 @@ protected JPQLQuery createQuery(Predicate... predicate) { return query; } - /** + /** + * Creates a new {@link JPADeleteClause} for the given {@link Predicate}. + * + * @param predicate + * @return the Querydsl {@link JPADeleteClause}. + */ + protected JPADeleteClause createDeleteClause(Predicate... predicate) { + JPADeleteClause deleteClause = deleteQuerydsl.createQuery().where(predicate); + CrudMethodMetadata metadata = getRepositoryMethodMetadata(); + + if (metadata == null) { + return deleteClause; + } + + LockModeType type = metadata.getLockModeType(); + deleteClause = type == null ? deleteClause : deleteClause.setLockMode(type); + + + return deleteClause; + } + + + /** * Creates a new {@link JPQLQuery} count query for the given {@link Predicate}. * * @param predicate, can be {@literal null}. @@ -205,7 +242,7 @@ protected JPQLQuery createCountQuery(Predicate predicate) { /** * Executes the given {@link JPQLQuery} after applying the given {@link OrderSpecifier}s. - * + * * @param query must not be {@literal null}. * @param orders must not be {@literal null}. * @return @@ -216,7 +253,7 @@ private List executeSorted(JPQLQuery query, OrderSpecifier... orders) { /** * Executes the given {@link JPQLQuery} after applying the given {@link Sort}. - * + * * @param query must not be {@literal null}. * @param sort must not be {@literal null}. * @return diff --git a/src/test/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepositoryTests.java b/src/test/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepositoryTests.java index 63f06c56bb..2de6a3750b 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepositoryTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepositoryTests.java @@ -92,6 +92,23 @@ public void executesPredicatesCorrectly() throws Exception { assertThat(result, hasItems(carter, dave)); } + @Test + public void executesDeletePredicatesCorrectly() throws Exception { + + BooleanExpression isCalledDave = user.firstname.eq("Dave"); + BooleanExpression isBeauford = user.lastname.eq("Beauford"); + + List result = repository.findAll(isCalledDave.or(isBeauford)); + + assertThat(result.size(), is(2)); + + repository.delete(isCalledDave); + + result = repository.findAll(isCalledDave.or(isBeauford)); + + assertThat(result.size(), is(1)); + } + @Test public void executesStringBasedPredicatesCorrectly() throws Exception {