diff --git a/src/main/java/org/springframework/data/jpa/repository/Modifying.java b/src/main/java/org/springframework/data/jpa/repository/Modifying.java index 1085ae88c..48158a7d9 100644 --- a/src/main/java/org/springframework/data/jpa/repository/Modifying.java +++ b/src/main/java/org/springframework/data/jpa/repository/Modifying.java @@ -26,12 +26,20 @@ import java.lang.annotation.Target; * * @author Oliver Gierke * @author Christoph Strobl + * @author Nicolas Cirigliano */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Documented public @interface Modifying { + /** + * Defines whether we should flush the underlying persistence context before executing the modifying query. + * + * @return + */ + boolean flushAutomatically() default false; + /** * Defines whether we should clear the underlying persistence context after executing the modifying query. * diff --git a/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java index 2006f12d0..43eadff72 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2017 the original author or authors. + * Copyright 2008-2018 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. @@ -49,6 +49,7 @@ import org.springframework.util.Assert; * @author Oliver Gierke * @author Thomas Darimont * @author Mark Paluch + * @author Nicolas Cirigliano */ public abstract class AbstractJpaQuery implements RepositoryQuery { @@ -134,7 +135,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery { } else if (method.isPageQuery()) { return new PagedExecution(method.getParameters()); } else if (method.isModifyingQuery()) { - return method.getClearAutomatically() ? new ModifyingExecution(method, em) : new ModifyingExecution(method, null); + return new ModifyingExecution(method, em); } else { return new SingleEntityExecution(); } 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 f135cab4d..d441938f0 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 @@ -1,5 +1,5 @@ /* - * Copyright 2008-2017 the original author or authors. + * Copyright 2008-2018 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. @@ -53,6 +53,7 @@ import org.springframework.util.ReflectionUtils; * @author Oliver Gierke * @author Thomas Darimont * @author Mark Paluch + * @author Nicolas Cirigliano */ public abstract class JpaQueryExecution { @@ -215,10 +216,13 @@ public abstract class JpaQueryExecution { static class ModifyingExecution extends JpaQueryExecution { private final EntityManager em; + private final boolean flush; + private final boolean clear; /** - * Creates an execution that automatically clears the given {@link EntityManager} after execution if the given - * {@link EntityManager} is not {@literal null}. + * Creates an execution that automatically flushes the given {@link EntityManager} before execution and/or + * clears the given {@link EntityManager} after execution if the given {@link EntityManager} is not + * {@literal null}. * * @param em */ @@ -232,14 +236,20 @@ public abstract class JpaQueryExecution { Assert.isTrue(isInt || isVoid, "Modifying queries can only use void or int/Integer as return type!"); this.em = em; + this.flush = method.getFlushAutomatically(); + this.clear = method.getClearAutomatically(); } @Override protected Object doExecute(AbstractJpaQuery query, Object[] values) { + if (em != null && flush) { + em.flush(); + } + int result = query.createQuery(values).executeUpdate(); - if (em != null) { + if (em != null && clear) { em.clear(); } diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java index af6d5d1dc..b1915c38a 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2017 the original author or authors. + * Copyright 2008-2018 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. @@ -49,6 +49,7 @@ import org.springframework.util.StringUtils; * @author Oliver Gierke * @author Thomas Darimont * @author Christoph Strobl + * @author Nicolas Cirigliano */ public class JpaQueryMethod extends QueryMethod { @@ -284,10 +285,19 @@ public class JpaQueryMethod extends QueryMethod { } /** - * Returns whether we should clear automatically for modifying queries. + * Returns whether we should flush automatically for modifying queries. * * @return */ + boolean getFlushAutomatically() { + return getMergedOrDefaultAnnotationValue("flushAutomatically", Modifying.class, Boolean.class); + } + + /** + * Returns whether we should clear automatically for modifying queries. + * + * @return + */ boolean getClearAutomatically() { return getMergedOrDefaultAnnotationValue("clearAutomatically", Modifying.class, Boolean.class); } diff --git a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java index e2a08fa10..683602f03 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java @@ -46,6 +46,7 @@ import org.springframework.data.repository.query.Parameters; * @author Oliver Gierke * @author Thomas Darimont * @author Mark Paluch + * @author Nicolas Cirigliano */ @RunWith(MockitoJUnitRunner.class) public class JpaQueryExecutionUnitTests { @@ -84,16 +85,35 @@ public class JpaQueryExecutionUnitTests { @Test @SuppressWarnings({ "unchecked", "rawtypes" }) - public void modifyingExecutionClearsEntityManagerIfSet() { + public void modifyingExecutionFlushesEntityManagerIfSet() { when(query.executeUpdate()).thenReturn(0); when(method.getReturnType()).thenReturn((Class) void.class); + when(method.getFlushAutomatically()).thenReturn(true); when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query); when(jpaQuery.getQueryMethod()).thenReturn(method); ModifyingExecution execution = new ModifyingExecution(method, em); execution.execute(jpaQuery, new Object[] {}); + verify(em, times(1)).flush(); + verify(em, times(0)).clear(); + } + + @Test + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void modifyingExecutionClearsEntityManagerIfSet() { + + when(query.executeUpdate()).thenReturn(0); + when(method.getReturnType()).thenReturn((Class) void.class); + when(method.getClearAutomatically()).thenReturn(true); + when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query); + when(jpaQuery.getQueryMethod()).thenReturn(method); + + ModifyingExecution execution = new ModifyingExecution(method, em); + execution.execute(jpaQuery, new Object[] {}); + + verify(em, times(0)).flush(); verify(em, times(1)).clear(); }