DATAJPA-1818 - Implements CrudRepository.deleteAllById(Iterable<ID> ids).

Handling of IN-Queries in Eclipselink is still broken so this properly works only with Hibernate.

Original pull request: #435.
This commit is contained in:
Jens Schauder
2020-11-11 07:20:08 +01:00
committed by Mark Paluch
parent e2db96193c
commit 38457e6d40
6 changed files with 94 additions and 16 deletions

View File

@@ -84,6 +84,19 @@ public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>,
*/
void deleteInBatch(Iterable<T> entities);
/**
* Deletes the entities identified by the given ids using a single {@link Query}.
*
* This kind of operation leaves JPAs first level cache and the database out of sync.
* Consider flushing the `EntityManager` before calling this method.
*
* @param ids
*
* @since 3.0
*/
void deleteAllByIdInBatch(Iterable<ID> ids);
/**
* Deletes all entities in a batch call.
*/

View File

@@ -86,6 +86,7 @@ public abstract class QueryUtils {
public static final String COUNT_QUERY_STRING = "select count(%s) from %s x";
public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";
public static final String DELETE_ALL_QUERY_BY_ID_STRING = "delete from %s x where %s in :ids";
// Used Regex/Unicode categories (see https://www.unicode.org/reports/tr18/#General_Category_Property):
// Z Separator

View File

@@ -218,6 +218,16 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
}
}
@Override
public void deleteAllById(Iterable<? extends ID> ids) {
Assert.notNull(ids, "Ids must not be null!");
for (ID id : ids) {
deleteById(id);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.JpaRepository#deleteInBatch(java.lang.Iterable)
@@ -236,6 +246,24 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
.executeUpdate();
}
@Override
public void deleteAllByIdInBatch(Iterable<ID> ids) {
Assert.notNull(ids, "Ids must not be null!");
if (!ids.iterator().hasNext()) {
return;
}
String queryTemplate = DELETE_ALL_QUERY_BY_ID_STRING;
String queryString = String.format(queryTemplate, entityInformation.getEntityName(), entityInformation.getIdAttribute().getName());
Query query = em.createQuery(queryString);
query.setParameter("ids", ids);
query.executeUpdate();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.Repository#deleteAll()

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.jpa.repository;
import static java.util.Arrays.*;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.domain.Example.*;
import static org.springframework.data.domain.ExampleMatcher.*;
@@ -151,7 +152,7 @@ public class UserRepositoryTests {
flushTestUsers();
assertThat(repository.findAllById(Arrays.asList(firstUser.getId(), secondUser.getId()))).contains(firstUser,
assertThat(repository.findAllById(asList(firstUser.getId(), secondUser.getId()))).contains(firstUser,
secondUser);
}
@@ -166,7 +167,7 @@ public class UserRepositoryTests {
@Test
void savesCollectionCorrectly() throws Exception {
assertThat(repository.saveAll(Arrays.asList(firstUser, secondUser, thirdUser))).hasSize(3).contains(firstUser,
assertThat(repository.saveAll(asList(firstUser, secondUser, thirdUser))).hasSize(3).contains(firstUser,
secondUser, thirdUser);
}
@@ -238,13 +239,13 @@ public class UserRepositoryTests {
}
@Test
void deleteColletionOfEntities() {
void deleteCollectionOfEntities() {
flushTestUsers();
long before = repository.count();
repository.deleteAll(Arrays.asList(firstUser, secondUser));
repository.deleteAll(asList(firstUser, secondUser));
assertThat(repository.existsById(firstUser.getId())).isFalse();
assertThat(repository.existsById(secondUser.getId())).isFalse();
@@ -252,13 +253,27 @@ public class UserRepositoryTests {
}
@Test
void batchDeleteColletionOfEntities() {
void batchDeleteCollectionOfEntities() {
flushTestUsers();
long before = repository.count();
repository.deleteInBatch(Arrays.asList(firstUser, secondUser));
repository.deleteInBatch(asList(firstUser, secondUser));
assertThat(repository.existsById(firstUser.getId())).isFalse();
assertThat(repository.existsById(secondUser.getId())).isFalse();
assertThat(repository.count()).isEqualTo(before - 2);
}
@Test // DATAJPA-1818
void deleteCollectionOfEntitiesById() {
flushTestUsers();
long before = repository.count();
repository.deleteAllById(asList(firstUser.getId(), secondUser.getId()));
assertThat(repository.existsById(firstUser.getId())).isFalse();
assertThat(repository.existsById(secondUser.getId())).isFalse();
@@ -603,7 +618,7 @@ public class UserRepositoryTests {
firstUser.setManager(secondUser);
thirdUser.setManager(firstUser);
repository.saveAll(Arrays.asList(firstUser, thirdUser));
repository.saveAll(asList(firstUser, thirdUser));
assertThat(repository.findByManagerLastname("Arrasz")).containsOnly(firstUser);
assertThat(repository.findByManagerLastname("Gierke")).containsOnly(thirdUser);
@@ -616,7 +631,7 @@ public class UserRepositoryTests {
firstUser.addColleague(secondUser);
thirdUser.addColleague(firstUser);
repository.saveAll(Arrays.asList(firstUser, thirdUser));
repository.saveAll(asList(firstUser, thirdUser));
assertThat(repository.findByColleaguesLastname(secondUser.getLastname())).containsOnly(firstUser);
@@ -1178,7 +1193,7 @@ public class UserRepositoryTests {
flushTestUsers();
List<User> result = repository.findByAttributesIn(new HashSet<>(Arrays.asList("cool", "hip")));
List<User> result = repository.findByAttributesIn(new HashSet<>(asList("cool", "hip")));
assertThat(result).containsOnly(firstUser, secondUser);
}
@@ -1731,7 +1746,7 @@ public class UserRepositoryTests {
firstUser.setManager(secondUser);
thirdUser.setManager(firstUser);
repository.saveAll(Arrays.asList(firstUser, thirdUser));
repository.saveAll(asList(firstUser, thirdUser));
User manager = new User();
manager.setLastname("Arrasz");
@@ -1854,7 +1869,7 @@ public class UserRepositoryTests {
fifthUser.setFirstname(firstUser.getFirstname());
fifthUser.setLastname(firstUser.getLastname());
repository.saveAll(Arrays.asList(firstUser, fifthUser));
repository.saveAll(asList(firstUser, fifthUser));
User prototype = new User();
prototype.setFirstname(firstUser.getFirstname());
@@ -2242,7 +2257,7 @@ public class UserRepositoryTests {
flushTestUsers();
List<User> result = repository.findByAttributesIgnoreCaseIn(new HashSet<>(Arrays.asList("cOOl", "hIP")));
List<User> result = repository.findByAttributesIgnoreCaseIn(new HashSet<>(asList("cOOl", "hIP")));
assertThat(result).containsOnly(firstUser, secondUser);
}
@@ -2256,7 +2271,7 @@ public class UserRepositoryTests {
flushTestUsers();
List<User> result = repository.findByAttributesIgnoreCaseNotIn(Arrays.asList("CooL", "HIp"));
List<User> result = repository.findByAttributesIgnoreCaseNotIn(asList("CooL", "HIp"));
assertThat(result).containsOnly(thirdUser);
}
@@ -2284,7 +2299,7 @@ public class UserRepositoryTests {
flushTestUsers();
List<User> result = repository.findByAttributesIgnoreCaseIn(Arrays.asList("cOOl", null));
List<User> result = repository.findByAttributesIgnoreCaseIn(asList("cOOl", null));
assertThat(result).containsOnly(firstUser);
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.jpa.repository.support;
import org.junit.jupiter.api.Disabled;
import org.springframework.test.context.ContextConfiguration;
/**
@@ -25,4 +26,11 @@ import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration("classpath:eclipselink.xml")
class EclipseLinkJpaRepositoryTests extends JpaRepositoryTests {
@Override
/**
* Ignored until https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477 is resolved.
*/
void deleteAllByIdInBatch() {
super.deleteAllByIdInBatch();
}
}

View File

@@ -114,11 +114,24 @@ class JpaRepositoryTests {
assertThat(idClassRepository.existsById(id)).isTrue();
}
private static interface SampleEntityRepository extends JpaRepository<SampleEntity, SampleEntityPK> {
@Test // DATAJPA-1818
void deleteAllByIdInBatch() {
SampleEntity one = new SampleEntity("one", "eins");
SampleEntity two = new SampleEntity("two", "zwei");
SampleEntity three = new SampleEntity("three", "drei");
repository.saveAll(Arrays.asList(one, two, three));
repository.flush();
repository.deleteAllByIdInBatch(Arrays.asList(new SampleEntityPK("one", "eins"),new SampleEntityPK("three", "drei")));
assertThat(repository.findAll()).containsExactly(two);
}
private interface SampleEntityRepository extends JpaRepository<SampleEntity, SampleEntityPK> {
}
private static interface SampleWithIdClassRepository
private interface SampleWithIdClassRepository
extends CrudRepository<PersistableWithIdClass, PersistableWithIdClassPK> {
}