Add insertAll and updateAll for JdbcAggregateOperations.

Original pull request #1396
Closes #1395
This commit is contained in:
mhyeon-lee
2022-12-17 21:17:55 +09:00
committed by Jens Schauder
parent 9d5c11e670
commit d10be27485
3 changed files with 99 additions and 16 deletions

View File

@@ -33,6 +33,7 @@ import org.springframework.lang.Nullable;
* @author Milan Milanov
* @author Chirag Tailor
* @author Diego Krupitza
* @author Myeonghyeon Lee
*/
public interface JdbcAggregateOperations {
@@ -71,6 +72,19 @@ public interface JdbcAggregateOperations {
*/
<T> T insert(T instance);
/**
* Inserts all aggregate instances, including all the members of each aggregate instance.
* <p>
* This is useful if the client provides an id for new aggregate roots.
* </p>
*
* @param instances the aggregate roots to be inserted. Must not be {@code null}.
* @param <T> the type of the aggregate root.
* @return the saved instances.
* @since 3.1
*/
<T> Iterable<T> insertAll(Iterable<T> instances);
/**
* Dedicated update function. This skips the test if the aggregate root is new or not and always performs an update
* operation.
@@ -81,6 +95,16 @@ public interface JdbcAggregateOperations {
*/
<T> T update(T instance);
/**
* Updates all aggregate instances, including all the members of each aggregate instance.
*
* @param instances the aggregate roots to be inserted. Must not be {@code null}.
* @param <T> the type of the aggregate root.
* @return the saved instances.
* @since 3.1
*/
<T> Iterable<T> updateAll(Iterable<T> instances);
/**
* Counts the number of aggregates of a given type.
*

View File

@@ -164,7 +164,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
Assert.notNull(instance, "Aggregate instance must not be null");
return performSave(instance, changeCreatorSelectorForSave(instance));
return performSave(new EntityAndChangeCreator<>(instance, changeCreatorSelectorForSave(instance)));
}
@Override
@@ -172,7 +172,11 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
Assert.isTrue(instances.iterator().hasNext(), "Aggregate instances must not be empty");
return performSaveAll(instances);
List<EntityAndChangeCreator<T>> entityAndChangeCreators = new ArrayList<>();
for (T instance : instances) {
entityAndChangeCreators.add(new EntityAndChangeCreator<>(instance, changeCreatorSelectorForSave(instance)));
}
return performSaveAll(entityAndChangeCreators);
}
/**
@@ -187,7 +191,21 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
Assert.notNull(instance, "Aggregate instance must not be null");
return performSave(instance, entity -> createInsertChange(prepareVersionForInsert(entity)));
return performSave(new EntityAndChangeCreator<>(
instance, entity -> createInsertChange(prepareVersionForInsert(entity))));
}
@Override
public <T> Iterable<T> insertAll(Iterable<T> instances) {
Assert.isTrue(instances.iterator().hasNext(), "Aggregate instances must not be empty");
List<EntityAndChangeCreator<T>> entityAndChangeCreators = new ArrayList<>();
for (T instance : instances) {
entityAndChangeCreators.add(new EntityAndChangeCreator<>(
instance, entity -> createInsertChange(prepareVersionForInsert(entity))));
}
return performSaveAll(entityAndChangeCreators);
}
/**
@@ -202,7 +220,21 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
Assert.notNull(instance, "Aggregate instance must not be null");
return performSave(instance, entity -> createUpdateChange(prepareVersionForUpdate(entity)));
return performSave(new EntityAndChangeCreator<>(
instance, entity -> createUpdateChange(prepareVersionForUpdate(entity))));
}
@Override
public <T> Iterable<T> updateAll(Iterable<T> instances) {
Assert.isTrue(instances.iterator().hasNext(), "Aggregate instances must not be empty");
List<EntityAndChangeCreator<T>> entityAndChangeCreators = new ArrayList<>();
for (T instance : instances) {
entityAndChangeCreators.add(new EntityAndChangeCreator<>(
instance, entity -> createUpdateChange(prepareVersionForUpdate(entity))));
}
return performSaveAll(entityAndChangeCreators);
}
@Override
@@ -401,13 +433,13 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
return triggerAfterSave(entityAfterExecution, change);
}
private <T> RootAggregateChange<T> beforeExecute(T aggregateRoot, Function<T, RootAggregateChange<T>> changeCreator) {
private <T> RootAggregateChange<T> beforeExecute(EntityAndChangeCreator<T> instance) {
Assert.notNull(aggregateRoot, "Aggregate instance must not be null");
Assert.notNull(instance.entity, "Aggregate instance must not be null");
aggregateRoot = triggerBeforeConvert(aggregateRoot);
T aggregateRoot = triggerBeforeConvert(instance.entity);
RootAggregateChange<T> change = changeCreator.apply(aggregateRoot);
RootAggregateChange<T> change = instance.changeCreator.apply(aggregateRoot);
aggregateRoot = triggerBeforeSave(change.getRoot(), change);
@@ -427,12 +459,12 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
triggerAfterDelete(entity, id, change);
}
private <T> T performSave(T instance, Function<T, RootAggregateChange<T>> changeCreator) {
private <T> T performSave(EntityAndChangeCreator<T> instance) {
// noinspection unchecked
BatchingAggregateChange<T, RootAggregateChange<T>> batchingAggregateChange = //
BatchingAggregateChange.forSave((Class<T>) ClassUtils.getUserClass(instance));
batchingAggregateChange.add(beforeExecute(instance, changeCreator));
BatchingAggregateChange.forSave((Class<T>) ClassUtils.getUserClass(instance.entity));
batchingAggregateChange.add(beforeExecute(instance));
Iterator<T> afterExecutionIterator = executor.executeSave(batchingAggregateChange).iterator();
@@ -441,16 +473,16 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
return afterExecute(batchingAggregateChange, afterExecutionIterator.next());
}
private <T> List<T> performSaveAll(Iterable<T> instances) {
private <T> List<T> performSaveAll(Iterable<EntityAndChangeCreator<T>> instances) {
BatchingAggregateChange<T, RootAggregateChange<T>> batchingAggregateChange = null;
for (T instance : instances) {
for (EntityAndChangeCreator<T> instance : instances) {
if (batchingAggregateChange == null) {
// noinspection unchecked
batchingAggregateChange = BatchingAggregateChange.forSave((Class<T>) ClassUtils.getUserClass(instance));
batchingAggregateChange = BatchingAggregateChange.forSave(
(Class<T>) ClassUtils.getUserClass(instance.entity));
}
batchingAggregateChange.add(beforeExecute(instance, changeCreatorSelectorForSave(instance)));
batchingAggregateChange.add(beforeExecute(instance));
}
Assert.notNull(batchingAggregateChange, "Iterable in saveAll must not be empty");
@@ -604,4 +636,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
private record EntityAndPreviousVersion<T> (T entity, @Nullable Number version) {
}
private record EntityAndChangeCreator<T> (T entity, Function<T, RootAggregateChange<T>> changeCreator) {
}
}

View File

@@ -384,6 +384,30 @@ class JdbcAggregateTemplateIntegrationTests {
assertThat(template.count(AggregateWithImmutableVersion.class)).isEqualTo(0);
}
@Test // GH-1395
void insertAndUpdateAllByAggregateRootsWithVersion() {
AggregateWithImmutableVersion aggregate1 = new AggregateWithImmutableVersion(null, null);
AggregateWithImmutableVersion aggregate2 = new AggregateWithImmutableVersion(null, null);
AggregateWithImmutableVersion aggregate3 = new AggregateWithImmutableVersion(null, null);
Iterator<AggregateWithImmutableVersion> savedAggregatesIterator = template
.insertAll(List.of(aggregate1, aggregate2, aggregate3)).iterator();
assertThat(template.count(AggregateWithImmutableVersion.class)).isEqualTo(3);
AggregateWithImmutableVersion savedAggregate1 = savedAggregatesIterator.next();
AggregateWithImmutableVersion twiceSavedAggregate2 = template.save(savedAggregatesIterator.next());
AggregateWithImmutableVersion twiceSavedAggregate3 = template.save(savedAggregatesIterator.next());
savedAggregatesIterator = template.updateAll(
List.of(savedAggregate1, twiceSavedAggregate2, twiceSavedAggregate3)).iterator();
assertThat(savedAggregatesIterator.next().version).isEqualTo(1);
assertThat(savedAggregatesIterator.next().version).isEqualTo(2);
assertThat(savedAggregatesIterator.next().version).isEqualTo(2);
AggregateWithImmutableVersion.clearConstructorInvocationData();
}
@Test // DATAJDBC-112
@EnabledOnFeature({ SUPPORTS_QUOTED_IDS, SUPPORTS_GENERATED_IDS_IN_REFERENCED_ENTITIES })
void updateReferencedEntityFromNull() {