Add insertAll and updateAll for JdbcAggregateOperations.
Original pull request #1396 Closes #1395
This commit is contained in:
committed by
Jens Schauder
parent
9d5c11e670
commit
d10be27485
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user