Add DeleteBatchingAggregateChange to batch DeleteRoot actions.
Original pull request #1231 See #537
This commit is contained in:
committed by
Jens Schauder
parent
483b30e8c2
commit
1a283fa406
@@ -98,6 +98,8 @@ class AggregateChangeExecutor {
|
||||
executionContext.executeDeleteAll((DbAction.DeleteAll<?>) action);
|
||||
} else if (action instanceof DbAction.DeleteRoot) {
|
||||
executionContext.executeDeleteRoot((DbAction.DeleteRoot<?>) action);
|
||||
} else if (action instanceof DbAction.BatchDeleteRoot) {
|
||||
executionContext.executeBatchDeleteRoot((DbAction.BatchDeleteRoot<?>) action);
|
||||
} else if (action instanceof DbAction.DeleteAllRoot) {
|
||||
executionContext.executeDeleteAllRoot((DbAction.DeleteAllRoot<?>) action);
|
||||
} else if (action instanceof DbAction.AcquireLockRoot) {
|
||||
|
||||
@@ -131,6 +131,12 @@ class JdbcAggregateChangeExecutionContext {
|
||||
}
|
||||
}
|
||||
|
||||
<T> void executeBatchDeleteRoot(DbAction.BatchDeleteRoot<T> batchDelete) {
|
||||
|
||||
List<Object> rootIds = batchDelete.getActions().stream().map(DbAction.DeleteRoot::getId).toList();
|
||||
accessStrategy.delete(rootIds, batchDelete.getEntityType());
|
||||
}
|
||||
|
||||
<T> void executeDelete(DbAction.Delete<T> delete) {
|
||||
|
||||
accessStrategy.delete(delete.getRootId(), delete.getPropertyPath());
|
||||
|
||||
@@ -79,6 +79,11 @@ public class CascadingDataAccessStrategy implements DataAccessStrategy {
|
||||
collectVoid(das -> das.delete(id, domainType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Iterable<Object> ids, Class<?> domainType) {
|
||||
collectVoid(das -> das.delete(ids, domainType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void deleteWithVersion(Object id, Class<T> domainType, Number previousVersion) {
|
||||
collectVoid(das -> das.deleteWithVersion(id, domainType, previousVersion));
|
||||
|
||||
@@ -130,6 +130,20 @@ public interface DataAccessStrategy extends RelationResolver {
|
||||
*/
|
||||
void delete(Object id, Class<?> domainType);
|
||||
|
||||
/**
|
||||
* Deletes multiple rows identified by the ids, from the table identified by the domainType. Does not handle cascading
|
||||
* deletes.
|
||||
* <P>
|
||||
* The statement will be of the form : {@code DELETE FROM … WHERE ID IN (:ids) } and throw an optimistic record
|
||||
* locking exception if no rows have been updated.
|
||||
*
|
||||
* @param ids the ids of the rows to be deleted. Must not be {@code null}.
|
||||
* @param domainType the type of entity to be deleted. Implicitly determines the table to operate on. Must not be
|
||||
* {@code null}.
|
||||
* @since 3.0
|
||||
*/
|
||||
void delete(Iterable<Object> ids, Class<?> domainType);
|
||||
|
||||
/**
|
||||
* Deletes a single entity from the database and enforce optimistic record locking using the version property. Does
|
||||
* not handle cascading deletes.
|
||||
@@ -155,7 +169,8 @@ public interface DataAccessStrategy extends RelationResolver {
|
||||
/**
|
||||
* Deletes all entities reachable via {@literal propertyPath} from the instances identified by {@literal rootIds}.
|
||||
*
|
||||
* @param rootIds Ids of the root objects on which the {@literal propertyPath} is based. Must not be {@code null} or empty.
|
||||
* @param rootIds Ids of the root objects on which the {@literal propertyPath} is based. Must not be {@code null} or
|
||||
* empty.
|
||||
* @param propertyPath Leading from the root object to the entities to be deleted. Must not be {@code null}.
|
||||
*/
|
||||
void delete(Iterable<Object> rootIds, PersistentPropertyPath<RelationalPersistentProperty> propertyPath);
|
||||
|
||||
@@ -163,6 +163,15 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
operations.update(deleteByIdSql, parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Iterable<Object> ids, Class<?> domainType) {
|
||||
|
||||
String deleteByIdInSql = sql(domainType).getDeleteByIdIn();
|
||||
SqlParameterSource parameter = sqlParametersFactory.forQueryByIds(ids, domainType);
|
||||
|
||||
operations.update(deleteByIdInSql, parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void deleteWithVersion(Object id, Class<T> domainType, Number previousVersion) {
|
||||
|
||||
|
||||
@@ -81,6 +81,11 @@ public class DelegatingDataAccessStrategy implements DataAccessStrategy {
|
||||
delegate.delete(id, domainType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Iterable<Object> ids, Class<?> domainType) {
|
||||
delegate.delete(ids, domainType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void deleteWithVersion(Object id, Class<T> domainType, Number previousVersion) {
|
||||
delegate.deleteWithVersion(id, domainType, previousVersion);
|
||||
|
||||
@@ -79,8 +79,10 @@ class SqlGenerator {
|
||||
private final Lazy<String> updateSql = Lazy.of(this::createUpdateSql);
|
||||
private final Lazy<String> updateWithVersionSql = Lazy.of(this::createUpdateWithVersionSql);
|
||||
|
||||
private final Lazy<String> deleteByIdSql = Lazy.of(this::createDeleteSql);
|
||||
private final Lazy<String> deleteByIdSql = Lazy.of(this::createDeleteByIdSql);
|
||||
private final Lazy<String> deleteByIdInSql = Lazy.of(this::createDeleteByIdInSql);
|
||||
private final Lazy<String> deleteByIdAndVersionSql = Lazy.of(this::createDeleteByIdAndVersionSql);
|
||||
private final Lazy<String> deleteByIdInAndVersionSql = Lazy.of(this::createDeleteByIdInAndVersionSql);
|
||||
private final Lazy<String> deleteByListSql = Lazy.of(this::createDeleteByListSql);
|
||||
|
||||
/**
|
||||
@@ -322,6 +324,15 @@ class SqlGenerator {
|
||||
return deleteByIdSql.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code DELETE FROM … WHERE :id IN …} statement.
|
||||
*
|
||||
* @return the statement as a {@link String}. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
String getDeleteByIdIn() {
|
||||
return deleteByIdInSql.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code DELETE FROM … WHERE :id = … and :___oldOptimisticLockingVersion = ...} statement.
|
||||
*
|
||||
@@ -331,6 +342,15 @@ class SqlGenerator {
|
||||
return deleteByIdAndVersionSql.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code DELETE FROM … WHERE :id In … and :___oldOptimisticLockingVersion = ...} statement.
|
||||
*
|
||||
* @return the statement as a {@link String}. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
String getDeleteByIdInAndVersion() {
|
||||
return deleteByIdInAndVersionSql.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code DELETE FROM … WHERE :ids in (…)} statement.
|
||||
*
|
||||
@@ -635,10 +655,14 @@ class SqlGenerator {
|
||||
.where(getIdColumn().isEqualTo(getBindMarker(entity.getIdColumn())));
|
||||
}
|
||||
|
||||
private String createDeleteSql() {
|
||||
private String createDeleteByIdSql() {
|
||||
return render(createBaseDeleteById(getTable()).build());
|
||||
}
|
||||
|
||||
private String createDeleteByIdInSql() {
|
||||
return render(createBaseDeleteByIdIn(getTable()).build());
|
||||
}
|
||||
|
||||
private String createDeleteByIdAndVersionSql() {
|
||||
|
||||
Delete delete = createBaseDeleteById(getTable()) //
|
||||
@@ -648,11 +672,25 @@ class SqlGenerator {
|
||||
return render(delete);
|
||||
}
|
||||
|
||||
private String createDeleteByIdInAndVersionSql() {
|
||||
|
||||
Delete delete = createBaseDeleteByIdIn(getTable()) //
|
||||
.and(getVersionColumn().isEqualTo(SQL.bindMarker(":" + renderReference(VERSION_SQL_PARAMETER)))) //
|
||||
.build();
|
||||
|
||||
return render(delete);
|
||||
}
|
||||
|
||||
private DeleteBuilder.DeleteWhereAndOr createBaseDeleteById(Table table) {
|
||||
return Delete.builder().from(table)
|
||||
.where(getIdColumn().isEqualTo(SQL.bindMarker(":" + renderReference(ID_SQL_PARAMETER))));
|
||||
}
|
||||
|
||||
private DeleteBuilder.DeleteWhereAndOr createBaseDeleteByIdIn(Table table) {
|
||||
return Delete.builder().from(table)
|
||||
.where(getIdColumn().in(SQL.bindMarker(":" + renderReference(IDS_SQL_PARAMETER))));
|
||||
}
|
||||
|
||||
private String createDeleteByPathAndCriteria(PersistentPropertyPathExtension path,
|
||||
Function<Column, Condition> rootCondition) {
|
||||
|
||||
|
||||
@@ -192,6 +192,11 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
sqlSession().delete(statement, parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Iterable<Object> ids, Class<?> domainType) {
|
||||
ids.forEach(id -> delete(id, domainType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void deleteWithVersion(Object id, Class<T> domainType, Number previousVersion) {
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -363,6 +364,25 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveAndDeleteAllByAggregateRootsWithVersion() {
|
||||
AggregateWithImmutableVersion aggregate1 = new AggregateWithImmutableVersion(null, null);
|
||||
AggregateWithImmutableVersion aggregate2 = new AggregateWithImmutableVersion(null, null);
|
||||
AggregateWithImmutableVersion aggregate3 = new AggregateWithImmutableVersion(null, null);
|
||||
Iterator<AggregateWithImmutableVersion> savedAggregatesIterator = template
|
||||
.saveAll(List.of(aggregate1, aggregate2, aggregate3)).iterator();
|
||||
AggregateWithImmutableVersion savedAggregate1 = savedAggregatesIterator.next();
|
||||
AggregateWithImmutableVersion twiceSavedAggregate2 = template.save(savedAggregatesIterator.next());
|
||||
AggregateWithImmutableVersion twiceSavedAggregate3 = template.save(savedAggregatesIterator.next());
|
||||
|
||||
assertThat(template.count(AggregateWithImmutableVersion.class)).isEqualTo(3);
|
||||
|
||||
template.deleteAll(List.of(savedAggregate1, twiceSavedAggregate2, twiceSavedAggregate3),
|
||||
AggregateWithImmutableVersion.class);
|
||||
|
||||
assertThat(template.count(AggregateWithImmutableVersion.class)).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
@EnabledOnFeature({ SUPPORTS_QUOTED_IDS, SUPPORTS_GENERATED_IDS_IN_REFERENCED_ENTITIES })
|
||||
void updateReferencedEntityFromNull() {
|
||||
|
||||
Reference in New Issue
Block a user