Skip to content

Commit 5ea4408

Browse files
committed
Determine and set the value for entity @Version before conversion to DbActions to simplify execution context.
1 parent 9260dc9 commit 5ea4408

File tree

12 files changed

+302
-164
lines changed

12 files changed

+302
-164
lines changed

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/AggregateChangeExecutor.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,6 @@ <T> T execute(AggregateChange<T> aggregateChange) {
5555
root = aggregateChange.getEntity();
5656
}
5757

58-
if (root != null) {
59-
root = executionContext.populateRootVersionIfNecessary(root);
60-
}
61-
6258
return root;
6359
}
6460

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateChangeExecutionContext.java

Lines changed: 7 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import org.springframework.data.mapping.context.MappingContext;
4141
import org.springframework.data.relational.core.conversion.DbAction;
4242
import org.springframework.data.relational.core.conversion.DbActionExecutionResult;
43-
import org.springframework.data.relational.core.conversion.RelationalEntityVersionUtils;
4443
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
4544
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
4645
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
@@ -65,7 +64,6 @@ class JdbcAggregateChangeExecutionContext {
6564
private final DataAccessStrategy accessStrategy;
6665

6766
private final Map<DbAction<?>, DbActionExecutionResult> results = new LinkedHashMap<>();
68-
@Nullable private Long version;
6967

7068
JdbcAggregateChangeExecutionContext(JdbcConverter converter, DataAccessStrategy accessStrategy) {
7169

@@ -76,28 +74,8 @@ class JdbcAggregateChangeExecutionContext {
7674

7775
<T> void executeInsertRoot(DbAction.InsertRoot<T> insert) {
7876

79-
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(insert.getEntityType());
80-
81-
Object id;
82-
if (persistentEntity.hasVersionProperty()) {
83-
84-
RelationalPersistentProperty versionProperty = persistentEntity.getVersionProperty();
85-
86-
Assert.state(versionProperty != null, "Version property must not be null at this stage.");
87-
88-
long initialVersion = versionProperty.getActualType().isPrimitive() ? 1L : 0;
89-
90-
T rootEntity = RelationalEntityVersionUtils.setVersionNumberOnEntity( //
91-
insert.getEntity(), initialVersion, persistentEntity, converter);
92-
93-
id = accessStrategy.insert(rootEntity, insert.getEntityType(), Identifier.empty(), insert.getIdValueSource());
94-
95-
setNewVersion(initialVersion);
96-
} else {
97-
id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), Identifier.empty(),
98-
insert.getIdValueSource());
99-
}
100-
77+
Object id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), Identifier.empty(),
78+
insert.getIdValueSource());
10179
add(new DbActionExecutionResult(insert, id));
10280
}
10381

@@ -125,12 +103,9 @@ <T> void executeInsertBatch(DbAction.InsertBatch<T> insertBatch) {
125103

126104
<T> void executeUpdateRoot(DbAction.UpdateRoot<T> update) {
127105

128-
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(update.getEntityType());
129-
130-
if (persistentEntity.hasVersionProperty()) {
131-
updateWithVersion(update, persistentEntity);
106+
if (update.getPreviousVersion() != null) {
107+
updateWithVersion(update);
132108
} else {
133-
134109
updateWithoutVersion(update);
135110
}
136111
}
@@ -252,36 +227,6 @@ private Object getIdFrom(DbAction.WithEntity<?> idOwningAction) {
252227
return identifier;
253228
}
254229

255-
private void setNewVersion(long version) {
256-
257-
Assert.isNull(this.version, "A new version was set a second time.");
258-
259-
this.version = version;
260-
}
261-
262-
private long getNewVersion() {
263-
264-
Assert.notNull(version, "A new version was requested, but none was set.");
265-
266-
return version;
267-
}
268-
269-
private boolean hasNewVersion() {
270-
return version != null;
271-
}
272-
273-
<T> T populateRootVersionIfNecessary(T newRoot) {
274-
275-
if (!hasNewVersion()) {
276-
return newRoot;
277-
}
278-
// Does the root entity have a version attribute?
279-
RelationalPersistentEntity<T> persistentEntity = (RelationalPersistentEntity<T>) context
280-
.getRequiredPersistentEntity(newRoot.getClass());
281-
282-
return RelationalEntityVersionUtils.setVersionNumberOnEntity(newRoot, getNewVersion(), persistentEntity, converter);
283-
}
284-
285230
@SuppressWarnings("unchecked")
286231
@Nullable
287232
<T> T populateIdsIfNecessary() {
@@ -372,20 +317,12 @@ private <T> void updateWithoutVersion(DbAction.UpdateRoot<T> update) {
372317
}
373318
}
374319

375-
private <T> void updateWithVersion(DbAction.UpdateRoot<T> update, RelationalPersistentEntity<T> persistentEntity) {
376-
377-
// If the root aggregate has a version property, increment it.
378-
Number previousVersion = RelationalEntityVersionUtils.getVersionNumberFromEntity(update.getEntity(),
379-
persistentEntity, converter);
320+
private <T> void updateWithVersion(DbAction.UpdateRoot<T> update) {
380321

322+
Number previousVersion = update.getPreviousVersion();
381323
Assert.notNull(previousVersion, "The root aggregate cannot be updated because the version property is null.");
382324

383-
setNewVersion(previousVersion.longValue() + 1);
384-
385-
T rootEntity = RelationalEntityVersionUtils.setVersionNumberOnEntity(update.getEntity(), getNewVersion(),
386-
persistentEntity, converter);
387-
388-
if (!accessStrategy.updateWithVersion(rootEntity, update.getEntityType(), previousVersion)) {
325+
if (!accessStrategy.updateWithVersion(update.getEntity(), update.getEntityType(), previousVersion)) {
389326

390327
throw new OptimisticLockingFailureException(String.format(UPDATE_FAILED_OPTIMISTIC_LOCKING, update.getEntity()));
391328
}

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535
import org.springframework.data.relational.core.conversion.RelationalEntityDeleteWriter;
3636
import org.springframework.data.relational.core.conversion.RelationalEntityInsertWriter;
3737
import org.springframework.data.relational.core.conversion.RelationalEntityUpdateWriter;
38+
import org.springframework.data.relational.core.conversion.RelationalEntityVersionUtils;
3839
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
3940
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
41+
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
4042
import org.springframework.data.relational.core.mapping.event.*;
4143
import org.springframework.data.support.PageableExecutionUtils;
4244
import org.springframework.lang.Nullable;
@@ -63,6 +65,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
6365

6466
private final DataAccessStrategy accessStrategy;
6567
private final AggregateChangeExecutor executor;
68+
private final JdbcConverter converter;
6669

6770
private EntityCallbacks entityCallbacks = EntityCallbacks.create();
6871

@@ -86,6 +89,7 @@ public JdbcAggregateTemplate(ApplicationContext publisher, RelationalMappingCont
8689
this.publisher = publisher;
8790
this.context = context;
8891
this.accessStrategy = dataAccessStrategy;
92+
this.converter = converter;
8993

9094
this.jdbcEntityInsertWriter = new RelationalEntityInsertWriter(context);
9195
this.jdbcEntityUpdateWriter = new RelationalEntityUpdateWriter(context);
@@ -115,6 +119,7 @@ public JdbcAggregateTemplate(ApplicationEventPublisher publisher, RelationalMapp
115119
this.publisher = publisher;
116120
this.context = context;
117121
this.accessStrategy = dataAccessStrategy;
122+
this.converter = converter;
118123

119124
this.jdbcEntityInsertWriter = new RelationalEntityInsertWriter(context);
120125
this.jdbcEntityUpdateWriter = new RelationalEntityUpdateWriter(context);
@@ -332,7 +337,7 @@ private <T> T store(T aggregateRoot, Function<T, MutableAggregateChange<T>> chan
332337

333338
MutableAggregateChange<T> change = changeCreator.apply(aggregateRoot);
334339

335-
aggregateRoot = triggerBeforeSave(aggregateRoot, change);
340+
aggregateRoot = triggerBeforeSave(change.getEntity(), change);
336341

337342
change.setEntity(aggregateRoot);
338343

@@ -359,21 +364,58 @@ private <T> void deleteTree(Object id, @Nullable T entity, Class<T> domainType)
359364

360365
private <T> MutableAggregateChange<T> createInsertChange(T instance) {
361366

362-
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forSave(instance);
363-
jdbcEntityInsertWriter.write(instance, aggregateChange);
367+
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(instance);
368+
T preparedInstance = instance;
369+
if (persistentEntity.hasVersionProperty()) {
370+
RelationalPersistentProperty versionProperty = persistentEntity.getRequiredVersionProperty();
371+
372+
long initialVersion = versionProperty.getActualType().isPrimitive() ? 1L : 0;
373+
374+
preparedInstance = RelationalEntityVersionUtils.setVersionNumberOnEntity( //
375+
instance, initialVersion, persistentEntity, converter);
376+
}
377+
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forSave(preparedInstance);
378+
jdbcEntityInsertWriter.write(preparedInstance, aggregateChange);
364379
return aggregateChange;
365380
}
366381

367382
private <T> MutableAggregateChange<T> createUpdateChange(T instance) {
368383

369-
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forSave(instance);
370-
jdbcEntityUpdateWriter.write(instance, aggregateChange);
384+
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(instance);
385+
T preparedInstance = instance;
386+
Number previousVersion = null;
387+
if (persistentEntity.hasVersionProperty()) {
388+
// If the root aggregate has a version property, increment it.
389+
previousVersion = RelationalEntityVersionUtils.getVersionNumberFromEntity(instance,
390+
persistentEntity, converter);
391+
392+
Assert.notNull(previousVersion, "The root aggregate cannot be updated because the version property is null.");
393+
394+
long newVersion = previousVersion.longValue() + 1;
395+
396+
preparedInstance = RelationalEntityVersionUtils.setVersionNumberOnEntity(instance, newVersion,
397+
persistentEntity, converter);
398+
}
399+
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forSave(preparedInstance, previousVersion);
400+
jdbcEntityUpdateWriter.write(preparedInstance, aggregateChange);
371401
return aggregateChange;
372402
}
373403

404+
@SuppressWarnings("unchecked")
405+
private <T> RelationalPersistentEntity<T> getRequiredPersistentEntity(T instance) {
406+
return (RelationalPersistentEntity<T>) context.getRequiredPersistentEntity(instance.getClass());
407+
}
408+
374409
private <T> MutableAggregateChange<T> createDeletingChange(Object id, @Nullable T entity, Class<T> domainType) {
375410

376-
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forDelete(domainType, entity);
411+
Number previousVersion = null;
412+
if (entity != null) {
413+
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(entity);
414+
if (persistentEntity.hasVersionProperty()) {
415+
previousVersion = RelationalEntityVersionUtils.getVersionNumberFromEntity(entity, persistentEntity, converter);
416+
}
417+
}
418+
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forDelete(domainType, entity, previousVersion);
377419
jdbcEntityDeleteWriter.write(id, aggregateChange);
378420
return aggregateChange;
379421
}

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateChangeExecutorContextImmutableUnitTests.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public void rootOfEmptySetOfActionsisNull() {
6464
}
6565

6666
@Test // DATAJDBC-453
67-
public void afterInsertRootIdAndVersionMaybeUpdated() {
67+
public void afterInsertRootIdMaybeUpdated() {
6868

6969
// note that the root entity isn't the original one, but a new instance with the version set.
7070
when(accessStrategy.insert(any(DummyEntity.class), eq(DummyEntity.class), eq(Identifier.empty()),
@@ -76,10 +76,6 @@ public void afterInsertRootIdAndVersionMaybeUpdated() {
7676

7777
assertThat(newRoot).isNotNull();
7878
assertThat(newRoot.id).isEqualTo(23L);
79-
80-
newRoot = executionContext.populateRootVersionIfNecessary(newRoot);
81-
82-
assertThat(newRoot.version).isEqualTo(1);
8379
}
8480

8581
@Test // DATAJDBC-453

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateChangeExecutorContextUnitTests.java

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public void rootOfEmptySetOfActionIsNull() {
7070
}
7171

7272
@Test // DATAJDBC-453
73-
public void afterInsertRootIdAndVersionMaybeUpdated() {
73+
public void afterInsertRootIdMaybeUpdated() {
7474

7575
when(accessStrategy.insert(root, DummyEntity.class, Identifier.empty(), IdValueSource.GENERATED)).thenReturn(23L);
7676

@@ -80,22 +80,6 @@ public void afterInsertRootIdAndVersionMaybeUpdated() {
8080

8181
assertThat(newRoot).isNull();
8282
assertThat(root.id).isEqualTo(23L);
83-
84-
executionContext.populateRootVersionIfNecessary(root);
85-
86-
assertThat(root.version).isEqualTo(1);
87-
}
88-
89-
@Test // DATAJDBC-507
90-
public void afterInsertNotPrimitiveVersionShouldBeZero() {
91-
92-
DummyEntityNonPrimitiveVersion dummyEntityNonPrimitiveVersion = new DummyEntityNonPrimitiveVersion();
93-
94-
executionContext
95-
.executeInsertRoot(new DbAction.InsertRoot<>(dummyEntityNonPrimitiveVersion, IdValueSource.GENERATED));
96-
executionContext.populateRootVersionIfNecessary(dummyEntityNonPrimitiveVersion);
97-
98-
assertThat(dummyEntityNonPrimitiveVersion.version).isEqualTo(0);
9983
}
10084

10185
@Test // DATAJDBC-453
@@ -218,19 +202,12 @@ PersistentPropertyPath<RelationalPersistentProperty> toPath(String path) {
218202
private static class DummyEntity {
219203

220204
@Id Long id;
221-
@Version long version;
222205

223206
Content content;
224207

225208
List<Content> list = new ArrayList<>();
226209
}
227210

228-
private static class DummyEntityNonPrimitiveVersion {
229-
230-
@Id Long id;
231-
@Version Long version;
232-
}
233-
234211
private static class Content {
235212
@Id Long id;
236213
}

0 commit comments

Comments
 (0)