Add DeleteBatchingAggregateChange to batch deletes when deleting multiple aggregate roots.
+ Rename DefaultAggregateChange to DeleteAggregateChange. Original pull request #1230
This commit is contained in:
committed by
Jens Schauder
parent
cf6e174088
commit
64a07e608d
@@ -80,6 +80,15 @@ public interface JdbcAggregateOperations {
|
||||
*/
|
||||
<T> void deleteById(Object id, Class<T> domainType);
|
||||
|
||||
/**
|
||||
* Deletes all aggregates identified by their aggregate root ids.
|
||||
*
|
||||
* @param ids the ids of the aggregate roots of the aggregates to be deleted. Must not be {@code null}.
|
||||
* @param domainType the type of the aggregate root.
|
||||
* @param <T> the type of the aggregate root.
|
||||
*/
|
||||
<T> void deleteAllById(Iterable<?> ids, Class<T> domainType);
|
||||
|
||||
/**
|
||||
* Delete an aggregate identified by it's aggregate root.
|
||||
*
|
||||
@@ -96,6 +105,15 @@ public interface JdbcAggregateOperations {
|
||||
*/
|
||||
void deleteAll(Class<?> domainType);
|
||||
|
||||
/**
|
||||
* Delete all aggregates identified by their aggregate roots.
|
||||
*
|
||||
* @param aggregateRoots to delete. Must not be {@code null}.
|
||||
* @param domainType type of the aggregate roots to be deleted. Must not be {@code null}.
|
||||
* @param <T> the type of the aggregate roots.
|
||||
*/
|
||||
<T> void deleteAll(Iterable<? extends T> aggregateRoots, Class<T> domainType);
|
||||
|
||||
/**
|
||||
* Counts the number of aggregates of a given type.
|
||||
*
|
||||
|
||||
@@ -17,7 +17,9 @@ package org.springframework.data.jdbc.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
@@ -33,6 +35,7 @@ import org.springframework.data.mapping.IdentifierAccessor;
|
||||
import org.springframework.data.mapping.callback.EntityCallbacks;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange;
|
||||
import org.springframework.data.relational.core.conversion.BatchingAggregateChange;
|
||||
import org.springframework.data.relational.core.conversion.DeleteAggregateChange;
|
||||
import org.springframework.data.relational.core.conversion.MutableAggregateChange;
|
||||
import org.springframework.data.relational.core.conversion.RelationalEntityDeleteWriter;
|
||||
import org.springframework.data.relational.core.conversion.RelationalEntityInsertWriter;
|
||||
@@ -275,6 +278,25 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
|
||||
deleteTree(id, null, domainType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void deleteAllById(Iterable<?> ids, Class<T> domainType) {
|
||||
|
||||
Assert.isTrue(ids.iterator().hasNext(), "Ids must not be empty!");
|
||||
|
||||
BatchingAggregateChange<T, DeleteAggregateChange<T>> batchingAggregateChange = BatchingAggregateChange
|
||||
.forDelete(domainType);
|
||||
|
||||
ids.forEach(id -> {
|
||||
DeleteAggregateChange<T> change = createDeletingChange(id, null, domainType);
|
||||
triggerBeforeDelete(null, id, change);
|
||||
batchingAggregateChange.add(change);
|
||||
});
|
||||
|
||||
executor.executeDelete(batchingAggregateChange);
|
||||
|
||||
ids.forEach(id -> triggerAfterDelete(null, id, batchingAggregateChange));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll(Class<?> domainType) {
|
||||
|
||||
@@ -284,6 +306,28 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
|
||||
executor.executeDelete(change);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void deleteAll(Iterable<? extends T> instances, Class<T> domainType) {
|
||||
|
||||
Assert.isTrue(instances.iterator().hasNext(), "Aggregate instances must not be empty!");
|
||||
|
||||
BatchingAggregateChange<T, DeleteAggregateChange<T>> batchingAggregateChange = BatchingAggregateChange
|
||||
.forDelete(domainType);
|
||||
Map<Object, T> instancesBeforeExecute = new LinkedHashMap<>();
|
||||
|
||||
instances.forEach(instance -> {
|
||||
Object id = context.getRequiredPersistentEntity(domainType).getIdentifierAccessor(instance)
|
||||
.getRequiredIdentifier();
|
||||
DeleteAggregateChange<T> change = createDeletingChange(id, instance, domainType);
|
||||
instancesBeforeExecute.put(id, triggerBeforeDelete(instance, id, change));
|
||||
batchingAggregateChange.add(change);
|
||||
});
|
||||
|
||||
executor.executeDelete(batchingAggregateChange);
|
||||
|
||||
instancesBeforeExecute.forEach((id, instance) -> triggerAfterDelete(instance, id, batchingAggregateChange));
|
||||
}
|
||||
|
||||
private <T> T afterExecute(AggregateChange<T> change, T entityAfterExecution) {
|
||||
|
||||
Object identifier = context.getRequiredPersistentEntity(change.getEntityType())
|
||||
@@ -416,7 +460,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
|
||||
return (RelationalPersistentEntity<T>) context.getRequiredPersistentEntity(instance.getClass());
|
||||
}
|
||||
|
||||
private <T> MutableAggregateChange<T> createDeletingChange(Object id, @Nullable T entity, Class<T> domainType) {
|
||||
private <T> DeleteAggregateChange<T> createDeletingChange(Object id, @Nullable T entity, Class<T> domainType) {
|
||||
|
||||
Number previousVersion = null;
|
||||
if (entity != null) {
|
||||
@@ -425,7 +469,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
|
||||
previousVersion = RelationalEntityVersionUtils.getVersionNumberFromEntity(entity, persistentEntity, converter);
|
||||
}
|
||||
}
|
||||
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forDelete(domainType, previousVersion);
|
||||
DeleteAggregateChange<T> aggregateChange = MutableAggregateChange.forDelete(domainType, previousVersion);
|
||||
jdbcEntityDeleteWriter.write(id, aggregateChange);
|
||||
return aggregateChange;
|
||||
}
|
||||
@@ -475,7 +519,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
|
||||
return entityCallbacks.callback(AfterSaveCallback.class, aggregateRoot);
|
||||
}
|
||||
|
||||
private <T> void triggerAfterDelete(@Nullable T aggregateRoot, Object id, MutableAggregateChange<T> change) {
|
||||
private <T> void triggerAfterDelete(@Nullable T aggregateRoot, Object id, AggregateChange<T> change) {
|
||||
|
||||
publisher.publishEvent(new AfterDeleteEvent<>(Identifier.of(id), aggregateRoot, change));
|
||||
|
||||
|
||||
@@ -101,14 +101,13 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T,ID>, Paging
|
||||
|
||||
@Override
|
||||
public void deleteAllById(Iterable<? extends ID> ids) {
|
||||
ids.forEach(it -> entityOperations.deleteById(it, entity.getType()));
|
||||
entityOperations.deleteAllById(ids, entity.getType());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void deleteAll(Iterable<? extends T> entities) {
|
||||
entities.forEach(it -> entityOperations.delete(it, (Class<T>) it.getClass()));
|
||||
entityOperations.deleteAll(entities, entity.getType());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
||||
@@ -331,6 +331,38 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // GH-537
|
||||
@EnabledOnFeature(SUPPORTS_QUOTED_IDS)
|
||||
void saveAndDeleteAllByAggregateRootsWithReferencedEntity() {
|
||||
LegoSet legoSet1 = template.save(legoSet);
|
||||
LegoSet legoSet2 = template.save(createLegoSet("Some Name"));
|
||||
|
||||
template.deleteAll(List.of(legoSet1, legoSet2), LegoSet.class);
|
||||
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
|
||||
assertThat(template.findAll(LegoSet.class)).isEmpty();
|
||||
assertThat(template.findAll(Manual.class)).isEmpty();
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // GH-537
|
||||
@EnabledOnFeature(SUPPORTS_QUOTED_IDS)
|
||||
void saveAndDeleteAllByIdsWithReferencedEntity() {
|
||||
LegoSet legoSet1 = template.save(legoSet);
|
||||
LegoSet legoSet2 = template.save(createLegoSet("Some Name"));
|
||||
|
||||
template.deleteAllById(List.of(legoSet1.id, legoSet2.id), LegoSet.class);
|
||||
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
|
||||
assertThat(template.findAll(LegoSet.class)).isEmpty();
|
||||
assertThat(template.findAll(Manual.class)).isEmpty();
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
@EnabledOnFeature({ SUPPORTS_QUOTED_IDS, SUPPORTS_GENERATED_IDS_IN_REFERENCED_ENTITIES })
|
||||
void updateReferencedEntityFromNull() {
|
||||
|
||||
Reference in New Issue
Block a user