Browse Source

Determine and set the value for entity @Version before conversion to DbActions to simplify execution context.

This change incorporates one test from https://github.com/spring-projects/spring-data-relational/pull/1150

Original pull request #1196
Closes #1137
pull/1209/head
Chirag Tailor 4 years ago committed by Jens Schauder
parent
commit
6500bfed3a
No known key found for this signature in database
GPG Key ID: 45CC872F17423DBF
  1. 6
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/AggregateChangeExecutor.java
  2. 85
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateChangeExecutionContext.java
  3. 57
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java
  4. 6
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateChangeExecutorContextImmutableUnitTests.java
  5. 25
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateChangeExecutorContextUnitTests.java
  6. 45
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java
  7. 160
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateUnitTests.java
  8. 10
      spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/DbAction.java
  9. 13
      spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/DefaultAggregateChange.java
  10. 37
      spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MutableAggregateChange.java
  11. 23
      spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/RelationalEntityDeleteWriter.java
  12. 6
      spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/WritingContext.java
  13. 57
      spring-data-relational/src/test/java/org/springframework/data/relational/core/conversion/RelationalEntityWriterUnitTests.java

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

@ -51,10 +51,8 @@ class AggregateChangeExecutor {
aggregateChange.forEachAction(action -> execute(action, executionContext)); aggregateChange.forEachAction(action -> execute(action, executionContext));
T root = executionContext.populateIdsIfNecessary(); T root = executionContext.populateIdsIfNecessary();
root = root == null ? aggregateChange.getEntity() : root; if (root == null) {
root = aggregateChange.getEntity();
if (root != null) {
root = executionContext.populateRootVersionIfNecessary(root);
} }
return root; return root;

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

@ -40,7 +40,6 @@ import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.relational.core.conversion.DbAction; import org.springframework.data.relational.core.conversion.DbAction;
import org.springframework.data.relational.core.conversion.DbActionExecutionResult; import org.springframework.data.relational.core.conversion.DbActionExecutionResult;
import org.springframework.data.relational.core.conversion.RelationalEntityVersionUtils;
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension; import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
@ -65,7 +64,6 @@ class JdbcAggregateChangeExecutionContext {
private final DataAccessStrategy accessStrategy; private final DataAccessStrategy accessStrategy;
private final Map<DbAction<?>, DbActionExecutionResult> results = new LinkedHashMap<>(); private final Map<DbAction<?>, DbActionExecutionResult> results = new LinkedHashMap<>();
@Nullable private Long version;
JdbcAggregateChangeExecutionContext(JdbcConverter converter, DataAccessStrategy accessStrategy) { JdbcAggregateChangeExecutionContext(JdbcConverter converter, DataAccessStrategy accessStrategy) {
@ -76,28 +74,8 @@ class JdbcAggregateChangeExecutionContext {
<T> void executeInsertRoot(DbAction.InsertRoot<T> insert) { <T> void executeInsertRoot(DbAction.InsertRoot<T> insert) {
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(insert.getEntityType()); Object id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), Identifier.empty(),
Object id;
if (persistentEntity.hasVersionProperty()) {
RelationalPersistentProperty versionProperty = persistentEntity.getVersionProperty();
Assert.state(versionProperty != null, "Version property must not be null at this stage.");
long initialVersion = versionProperty.getActualType().isPrimitive() ? 1L : 0;
T rootEntity = RelationalEntityVersionUtils.setVersionNumberOnEntity( //
insert.getEntity(), initialVersion, persistentEntity, converter);
id = accessStrategy.insert(rootEntity, insert.getEntityType(), Identifier.empty(), insert.getIdValueSource());
setNewVersion(initialVersion);
} else {
id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), Identifier.empty(),
insert.getIdValueSource()); insert.getIdValueSource());
}
add(new DbActionExecutionResult(insert, id)); add(new DbActionExecutionResult(insert, id));
} }
@ -125,12 +103,9 @@ class JdbcAggregateChangeExecutionContext {
<T> void executeUpdateRoot(DbAction.UpdateRoot<T> update) { <T> void executeUpdateRoot(DbAction.UpdateRoot<T> update) {
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(update.getEntityType()); if (update.getPreviousVersion() != null) {
updateWithVersion(update);
if (persistentEntity.hasVersionProperty()) {
updateWithVersion(update, persistentEntity);
} else { } else {
updateWithoutVersion(update); updateWithoutVersion(update);
} }
} }
@ -147,17 +122,11 @@ class JdbcAggregateChangeExecutionContext {
<T> void executeDeleteRoot(DbAction.DeleteRoot<T> delete) { <T> void executeDeleteRoot(DbAction.DeleteRoot<T> delete) {
if (delete.getPreviousVersion() != null) { if (delete.getPreviousVersion() != null) {
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(delete.getEntityType());
if (persistentEntity.hasVersionProperty()) {
accessStrategy.deleteWithVersion(delete.getId(), delete.getEntityType(), delete.getPreviousVersion()); accessStrategy.deleteWithVersion(delete.getId(), delete.getEntityType(), delete.getPreviousVersion());
return; } else {
}
}
accessStrategy.delete(delete.getId(), delete.getEntityType()); accessStrategy.delete(delete.getId(), delete.getEntityType());
} }
}
<T> void executeDelete(DbAction.Delete<T> delete) { <T> void executeDelete(DbAction.Delete<T> delete) {
@ -258,36 +227,6 @@ class JdbcAggregateChangeExecutionContext {
return identifier; return identifier;
} }
private void setNewVersion(long version) {
Assert.isNull(this.version, "A new version was set a second time.");
this.version = version;
}
private long getNewVersion() {
Assert.notNull(version, "A new version was requested, but none was set.");
return version;
}
private boolean hasNewVersion() {
return version != null;
}
<T> T populateRootVersionIfNecessary(T newRoot) {
if (!hasNewVersion()) {
return newRoot;
}
// Does the root entity have a version attribute?
RelationalPersistentEntity<T> persistentEntity = (RelationalPersistentEntity<T>) context
.getRequiredPersistentEntity(newRoot.getClass());
return RelationalEntityVersionUtils.setVersionNumberOnEntity(newRoot, getNewVersion(), persistentEntity, converter);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable @Nullable
<T> T populateIdsIfNecessary() { <T> T populateIdsIfNecessary() {
@ -378,20 +317,12 @@ class JdbcAggregateChangeExecutionContext {
} }
} }
private <T> void updateWithVersion(DbAction.UpdateRoot<T> update, RelationalPersistentEntity<T> persistentEntity) { private <T> void updateWithVersion(DbAction.UpdateRoot<T> update) {
// If the root aggregate has a version property, increment it.
Number previousVersion = RelationalEntityVersionUtils.getVersionNumberFromEntity(update.getEntity(),
persistentEntity, converter);
Number previousVersion = update.getPreviousVersion();
Assert.notNull(previousVersion, "The root aggregate cannot be updated because the version property is null."); Assert.notNull(previousVersion, "The root aggregate cannot be updated because the version property is null.");
setNewVersion(previousVersion.longValue() + 1); if (!accessStrategy.updateWithVersion(update.getEntity(), update.getEntityType(), previousVersion)) {
T rootEntity = RelationalEntityVersionUtils.setVersionNumberOnEntity(update.getEntity(), getNewVersion(),
persistentEntity, converter);
if (!accessStrategy.updateWithVersion(rootEntity, update.getEntityType(), previousVersion)) {
throw new OptimisticLockingFailureException(String.format(UPDATE_FAILED_OPTIMISTIC_LOCKING, update.getEntity())); throw new OptimisticLockingFailureException(String.format(UPDATE_FAILED_OPTIMISTIC_LOCKING, update.getEntity()));
} }

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2017-2021 the original author or authors. * Copyright 2017-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,8 +35,10 @@ import org.springframework.data.relational.core.conversion.MutableAggregateChang
import org.springframework.data.relational.core.conversion.RelationalEntityDeleteWriter; import org.springframework.data.relational.core.conversion.RelationalEntityDeleteWriter;
import org.springframework.data.relational.core.conversion.RelationalEntityInsertWriter; import org.springframework.data.relational.core.conversion.RelationalEntityInsertWriter;
import org.springframework.data.relational.core.conversion.RelationalEntityUpdateWriter; import org.springframework.data.relational.core.conversion.RelationalEntityUpdateWriter;
import org.springframework.data.relational.core.conversion.RelationalEntityVersionUtils;
import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.data.relational.core.mapping.event.*; import org.springframework.data.relational.core.mapping.event.*;
import org.springframework.data.support.PageableExecutionUtils; import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -51,6 +53,7 @@ import org.springframework.util.Assert;
* @author Christoph Strobl * @author Christoph Strobl
* @author Milan Milanov * @author Milan Milanov
* @author Myeonghyeon Lee * @author Myeonghyeon Lee
* @author Chirag Tailor
*/ */
public class JdbcAggregateTemplate implements JdbcAggregateOperations { public class JdbcAggregateTemplate implements JdbcAggregateOperations {
@ -63,6 +66,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
private final DataAccessStrategy accessStrategy; private final DataAccessStrategy accessStrategy;
private final AggregateChangeExecutor executor; private final AggregateChangeExecutor executor;
private final JdbcConverter converter;
private EntityCallbacks entityCallbacks = EntityCallbacks.create(); private EntityCallbacks entityCallbacks = EntityCallbacks.create();
@ -86,6 +90,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
this.publisher = publisher; this.publisher = publisher;
this.context = context; this.context = context;
this.accessStrategy = dataAccessStrategy; this.accessStrategy = dataAccessStrategy;
this.converter = converter;
this.jdbcEntityInsertWriter = new RelationalEntityInsertWriter(context); this.jdbcEntityInsertWriter = new RelationalEntityInsertWriter(context);
this.jdbcEntityUpdateWriter = new RelationalEntityUpdateWriter(context); this.jdbcEntityUpdateWriter = new RelationalEntityUpdateWriter(context);
@ -115,6 +120,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
this.publisher = publisher; this.publisher = publisher;
this.context = context; this.context = context;
this.accessStrategy = dataAccessStrategy; this.accessStrategy = dataAccessStrategy;
this.converter = converter;
this.jdbcEntityInsertWriter = new RelationalEntityInsertWriter(context); this.jdbcEntityInsertWriter = new RelationalEntityInsertWriter(context);
this.jdbcEntityUpdateWriter = new RelationalEntityUpdateWriter(context); this.jdbcEntityUpdateWriter = new RelationalEntityUpdateWriter(context);
@ -288,7 +294,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
MutableAggregateChange<T> change = changeCreator.apply(aggregateRoot); MutableAggregateChange<T> change = changeCreator.apply(aggregateRoot);
aggregateRoot = triggerBeforeSave(aggregateRoot, change); aggregateRoot = triggerBeforeSave(change.getEntity(), change);
change.setEntity(aggregateRoot); change.setEntity(aggregateRoot);
@ -315,21 +321,58 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
private <T> MutableAggregateChange<T> createInsertChange(T instance) { private <T> MutableAggregateChange<T> createInsertChange(T instance) {
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forSave(instance); RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(instance);
jdbcEntityInsertWriter.write(instance, aggregateChange); T preparedInstance = instance;
if (persistentEntity.hasVersionProperty()) {
RelationalPersistentProperty versionProperty = persistentEntity.getRequiredVersionProperty();
long initialVersion = versionProperty.getActualType().isPrimitive() ? 1L : 0;
preparedInstance = RelationalEntityVersionUtils.setVersionNumberOnEntity( //
instance, initialVersion, persistentEntity, converter);
}
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forSave(preparedInstance);
jdbcEntityInsertWriter.write(preparedInstance, aggregateChange);
return aggregateChange; return aggregateChange;
} }
private <T> MutableAggregateChange<T> createUpdateChange(T instance) { private <T> MutableAggregateChange<T> createUpdateChange(T instance) {
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forSave(instance); RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(instance);
jdbcEntityUpdateWriter.write(instance, aggregateChange); T preparedInstance = instance;
Number previousVersion = null;
if (persistentEntity.hasVersionProperty()) {
// If the root aggregate has a version property, increment it.
previousVersion = RelationalEntityVersionUtils.getVersionNumberFromEntity(instance,
persistentEntity, converter);
Assert.notNull(previousVersion, "The root aggregate cannot be updated because the version property is null.");
long newVersion = previousVersion.longValue() + 1;
preparedInstance = RelationalEntityVersionUtils.setVersionNumberOnEntity(instance, newVersion,
persistentEntity, converter);
}
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forSave(preparedInstance, previousVersion);
jdbcEntityUpdateWriter.write(preparedInstance, aggregateChange);
return aggregateChange; return aggregateChange;
} }
@SuppressWarnings("unchecked")
private <T> RelationalPersistentEntity<T> getRequiredPersistentEntity(T instance) {
return (RelationalPersistentEntity<T>) context.getRequiredPersistentEntity(instance.getClass());
}
private <T> MutableAggregateChange<T> createDeletingChange(Object id, @Nullable T entity, Class<T> domainType) { private <T> MutableAggregateChange<T> createDeletingChange(Object id, @Nullable T entity, Class<T> domainType) {
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forDelete(domainType, entity); Number previousVersion = null;
if (entity != null) {
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(entity);
if (persistentEntity.hasVersionProperty()) {
previousVersion = RelationalEntityVersionUtils.getVersionNumberFromEntity(entity, persistentEntity, converter);
}
}
MutableAggregateChange<T> aggregateChange = MutableAggregateChange.forDelete(domainType, entity, previousVersion);
jdbcEntityDeleteWriter.write(id, aggregateChange); jdbcEntityDeleteWriter.write(id, aggregateChange);
return aggregateChange; return aggregateChange;
} }

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

@ -64,7 +64,7 @@ public class JdbcAggregateChangeExecutorContextImmutableUnitTests {
} }
@Test // DATAJDBC-453 @Test // DATAJDBC-453
public void afterInsertRootIdAndVersionMaybeUpdated() { public void afterInsertRootIdMaybeUpdated() {
// note that the root entity isn't the original one, but a new instance with the version set. // note that the root entity isn't the original one, but a new instance with the version set.
when(accessStrategy.insert(any(DummyEntity.class), eq(DummyEntity.class), eq(Identifier.empty()), when(accessStrategy.insert(any(DummyEntity.class), eq(DummyEntity.class), eq(Identifier.empty()),
@ -76,10 +76,6 @@ public class JdbcAggregateChangeExecutorContextImmutableUnitTests {
assertThat(newRoot).isNotNull(); assertThat(newRoot).isNotNull();
assertThat(newRoot.id).isEqualTo(23L); assertThat(newRoot.id).isEqualTo(23L);
newRoot = executionContext.populateRootVersionIfNecessary(newRoot);
assertThat(newRoot.version).isEqualTo(1);
} }
@Test // DATAJDBC-453 @Test // DATAJDBC-453

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

@ -70,7 +70,7 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
} }
@Test // DATAJDBC-453 @Test // DATAJDBC-453
public void afterInsertRootIdAndVersionMaybeUpdated() { public void afterInsertRootIdMaybeUpdated() {
when(accessStrategy.insert(root, DummyEntity.class, Identifier.empty(), IdValueSource.GENERATED)).thenReturn(23L); when(accessStrategy.insert(root, DummyEntity.class, Identifier.empty(), IdValueSource.GENERATED)).thenReturn(23L);
@ -80,22 +80,6 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
assertThat(newRoot).isNull(); assertThat(newRoot).isNull();
assertThat(root.id).isEqualTo(23L); assertThat(root.id).isEqualTo(23L);
executionContext.populateRootVersionIfNecessary(root);
assertThat(root.version).isEqualTo(1);
}
@Test // DATAJDBC-507
public void afterInsertNotPrimitiveVersionShouldBeZero() {
DummyEntityNonPrimitiveVersion dummyEntityNonPrimitiveVersion = new DummyEntityNonPrimitiveVersion();
executionContext
.executeInsertRoot(new DbAction.InsertRoot<>(dummyEntityNonPrimitiveVersion, IdValueSource.GENERATED));
executionContext.populateRootVersionIfNecessary(dummyEntityNonPrimitiveVersion);
assertThat(dummyEntityNonPrimitiveVersion.version).isEqualTo(0);
} }
@Test // DATAJDBC-453 @Test // DATAJDBC-453
@ -218,19 +202,12 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
private static class DummyEntity { private static class DummyEntity {
@Id Long id; @Id Long id;
@Version long version;
Content content; Content content;
List<Content> list = new ArrayList<>(); List<Content> list = new ArrayList<>();
} }
private static class DummyEntityNonPrimitiveVersion {
@Id Long id;
@Version Long version;
}
private static class Content { private static class Content {
@Id Long id; @Id Long id;
} }

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

@ -819,6 +819,32 @@ class JdbcAggregateTemplateIntegrationTests {
.hasRootCauseInstanceOf(OptimisticLockingFailureException.class); .hasRootCauseInstanceOf(OptimisticLockingFailureException.class);
} }
@Test // GH-1137
void testUpdateEntityWithVersionDoesNotTriggerAnewConstructorInvocation() {
AggregateWithImmutableVersion aggregateWithImmutableVersion = new AggregateWithImmutableVersion(null, null);
final AggregateWithImmutableVersion savedRoot = template.save(aggregateWithImmutableVersion);
assertThat(savedRoot).isNotNull();
assertThat(savedRoot.version).isEqualTo(0L);
assertThat(AggregateWithImmutableVersion.constructorInvocations).containsExactly(
new ConstructorInvocation(null, null), // Initial invocation, done by client
new ConstructorInvocation(null, savedRoot.version), // Assigning the version
new ConstructorInvocation(savedRoot.id, savedRoot.version) // Assigning the id
);
AggregateWithImmutableVersion.clearConstructorInvocationData();
final AggregateWithImmutableVersion updatedRoot = template.save(savedRoot);
assertThat(updatedRoot).isNotNull();
assertThat(updatedRoot.version).isEqualTo(1L);
// Expect only one assignnment of the version to AggregateWithImmutableVersion
assertThat(AggregateWithImmutableVersion.constructorInvocations).containsOnly(new ConstructorInvocation(savedRoot.id, updatedRoot.version));
}
@Test // DATAJDBC-219 Test that a delete with a version attribute works as expected. @Test // DATAJDBC-219 Test that a delete with a version attribute works as expected.
void deleteAggregateWithVersion() { void deleteAggregateWithVersion() {
@ -1227,6 +1253,25 @@ class JdbcAggregateTemplateIntegrationTests {
@Id Long id; @Id Long id;
@Version Long version; @Version Long version;
private final static List<ConstructorInvocation> constructorInvocations = new ArrayList<>();
public static void clearConstructorInvocationData() {
constructorInvocations.clear();
}
public AggregateWithImmutableVersion(Long id, Long version) {
constructorInvocations.add(new ConstructorInvocation(id, version));
this.id = id;
this.version = version;
}
}
@Value
@EqualsAndHashCode
private static class ConstructorInvocation {
private Long id;
private Long version;
} }
@Data @Data

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 the original author or authors. * Copyright 2019-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,13 +23,16 @@ import static org.mockito.Mockito.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter; import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
@ -55,6 +58,7 @@ import org.springframework.data.relational.core.mapping.event.BeforeSaveCallback
* @author Christoph Strobl * @author Christoph Strobl
* @author Mark Paluch * @author Mark Paluch
* @author Milan Milanov * @author Milan Milanov
* @author Chirag Tailor
*/ */
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class JdbcAggregateTemplateUnitTests { public class JdbcAggregateTemplateUnitTests {
@ -111,6 +115,124 @@ public class JdbcAggregateTemplateUnitTests {
assertThat(last).isEqualTo(third); assertThat(last).isEqualTo(third);
} }
@Test
void savePreparesInstanceWithInitialVersion_onInsert() {
EntityWithVersion entity = new EntityWithVersion(1L);
when(callbacks.callback(any(), any(), any())).thenReturn(entity, entity);
template.save(entity);
ArgumentCaptor<Object> aggregateRootCaptor = ArgumentCaptor.forClass(Object.class);
verify(callbacks).callback(eq(BeforeSaveCallback.class), aggregateRootCaptor.capture(), any());
EntityWithVersion afterConvert = (EntityWithVersion) aggregateRootCaptor.getValue();
assertThat(afterConvert.getVersion()).isEqualTo(0L);
}
@Test
void savePreparesInstanceWithInitialVersion_onInsert_whenVersionPropertyIsImmutable() {
EntityWithImmutableVersion entity = new EntityWithImmutableVersion(1L, null);
when(callbacks.callback(any(), any(), any())).thenReturn(entity, entity);
template.save(entity);
ArgumentCaptor<Object> aggregateRootCaptor = ArgumentCaptor.forClass(Object.class);
verify(callbacks).callback(eq(BeforeSaveCallback.class), aggregateRootCaptor.capture(), any());
EntityWithImmutableVersion afterConvert = (EntityWithImmutableVersion) aggregateRootCaptor.getValue();
assertThat(afterConvert.getVersion()).isEqualTo(0L);
}
@Test // DATAJDBC-507
void savePreparesInstanceWithInitialVersion_onInsert_whenVersionPropertyIsPrimitiveType() {
EntityWithPrimitiveVersion entity = new EntityWithPrimitiveVersion(1L);
when(callbacks.callback(any(), any(), any())).thenReturn(entity, entity);
template.save(entity);
ArgumentCaptor<Object> aggregateRootCaptor = ArgumentCaptor.forClass(Object.class);
verify(callbacks).callback(eq(BeforeSaveCallback.class), aggregateRootCaptor.capture(), any());
EntityWithPrimitiveVersion afterConvert = (EntityWithPrimitiveVersion) aggregateRootCaptor.getValue();
assertThat(afterConvert.getVersion()).isEqualTo(1L);
}
@Test // DATAJDBC-507
void savePreparesInstanceWithInitialVersion_onInsert__whenVersionPropertyIsImmutableAndPrimitiveType() {
EntityWithImmutablePrimitiveVersion entity = new EntityWithImmutablePrimitiveVersion(1L, 0L);
when(callbacks.callback(any(), any(), any())).thenReturn(entity, entity);
template.save(entity);
ArgumentCaptor<Object> aggregateRootCaptor = ArgumentCaptor.forClass(Object.class);
verify(callbacks).callback(eq(BeforeSaveCallback.class), aggregateRootCaptor.capture(), any());
EntityWithImmutablePrimitiveVersion afterConvert = (EntityWithImmutablePrimitiveVersion) aggregateRootCaptor.getValue();
assertThat(afterConvert.getVersion()).isEqualTo(1L);
}
@Test
void savePreparesChangeWithPreviousVersion_onUpdate() {
when(dataAccessStrategy.updateWithVersion(any(), any(), any())).thenReturn(true);
EntityWithVersion entity = new EntityWithVersion(1L);
entity.setVersion(1L);
when(callbacks.callback(any(), any(), any())).thenReturn(entity, entity);
template.save(entity);
ArgumentCaptor<Object> aggregateChangeCaptor = ArgumentCaptor.forClass(Object.class);
verify(callbacks).callback(eq(BeforeSaveCallback.class), any(), aggregateChangeCaptor.capture());
MutableAggregateChange<?> aggregateChange = (MutableAggregateChange<?>) aggregateChangeCaptor.getValue();
assertThat(aggregateChange.getPreviousVersion()).isEqualTo(1L);
}
@Test
void savePreparesInstanceWithNextVersion_onUpdate() {
when(dataAccessStrategy.updateWithVersion(any(), any(), any())).thenReturn(true);
EntityWithVersion entity = new EntityWithVersion(1L);
entity.setVersion(1L);
when(callbacks.callback(any(), any(), any())).thenReturn(entity, entity);
template.save(entity);
ArgumentCaptor<Object> aggregateRootCaptor = ArgumentCaptor.forClass(Object.class);
verify(callbacks).callback(eq(BeforeSaveCallback.class), aggregateRootCaptor.capture(), any());
EntityWithVersion afterConvert = (EntityWithVersion) aggregateRootCaptor.getValue();
assertThat(afterConvert.getVersion()).isEqualTo(2L);
}
@Test
void savePreparesInstanceWithNextVersion_onUpdate_whenVersionPropertyIsImmutable() {
when(dataAccessStrategy.updateWithVersion(any(), any(), any())).thenReturn(true);
EntityWithImmutableVersion entity = new EntityWithImmutableVersion(1L, 1L);
when(callbacks.callback(any(), any(), any())).thenReturn(entity, entity);
template.save(entity);
ArgumentCaptor<Object> aggregateRootCaptor = ArgumentCaptor.forClass(Object.class);
verify(callbacks).callback(eq(BeforeSaveCallback.class), aggregateRootCaptor.capture(), any());
EntityWithImmutableVersion afterConvert = (EntityWithImmutableVersion) aggregateRootCaptor.getValue();
assertThat(afterConvert.getVersion()).isEqualTo(2L);
}
@Test
void deletePreparesChangeWithPreviousVersion_onDeleteByInstance() {
EntityWithImmutableVersion entity = new EntityWithImmutableVersion(1L, 1L);
when(callbacks.callback(any(), any(), any())).thenReturn(entity, entity);
template.delete(entity, EntityWithImmutableVersion.class);
ArgumentCaptor<Object> aggregateChangeCaptor = ArgumentCaptor.forClass(Object.class);
verify(callbacks).callback(eq(BeforeDeleteCallback.class), any(), aggregateChangeCaptor.capture());
MutableAggregateChange<?> aggregateChange = (MutableAggregateChange<?>) aggregateChangeCaptor.getValue();
assertThat(aggregateChange.getPreviousVersion()).isEqualTo(1L);
}
@Test // DATAJDBC-393 @Test // DATAJDBC-393
public void callbackOnDelete() { public void callbackOnDelete() {
@ -209,4 +331,40 @@ public class JdbcAggregateTemplateUnitTests {
private String name; private String name;
} }
@Data
@RequiredArgsConstructor
private static class EntityWithVersion {
@Column("id1") @Id private final Long id;
@Version private Long version;
}
@Data
@RequiredArgsConstructor
private static class EntityWithImmutableVersion {
@Column("id1") @Id private final Long id;
@Version private final Long version;
}
@Data
@RequiredArgsConstructor
private static class EntityWithPrimitiveVersion {
@Column("id1") @Id private final Long id;
@Version private long version;
}
@Data
@RequiredArgsConstructor
private static class EntityWithImmutablePrimitiveVersion {
@Column("id1") @Id private final Long id;
@Version private final long version;
}
} }

10
spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/DbAction.java

@ -166,14 +166,22 @@ public interface DbAction<T> {
private final T entity; private final T entity;
public UpdateRoot(T entity) { @Nullable private final Number previousVersion;
public UpdateRoot(T entity, @Nullable Number previousVersion) {
this.entity = entity; this.entity = entity;
this.previousVersion = previousVersion;
} }
public T getEntity() { public T getEntity() {
return this.entity; return this.entity;
} }
@Nullable
public Number getPreviousVersion() {
return previousVersion;
}
public String toString() { public String toString() {
return "DbAction.UpdateRoot(entity=" + this.getEntity() + ")"; return "DbAction.UpdateRoot(entity=" + this.getEntity() + ")";
} }

13
spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/DefaultAggregateChange.java

@ -27,6 +27,7 @@ import org.springframework.util.Assert;
* *
* @author Jens Schauder * @author Jens Schauder
* @author Mark Paluch * @author Mark Paluch
* @author Chirag Tailor
* @since 2.0 * @since 2.0
*/ */
class DefaultAggregateChange<T> implements MutableAggregateChange<T> { class DefaultAggregateChange<T> implements MutableAggregateChange<T> {
@ -41,11 +42,15 @@ class DefaultAggregateChange<T> implements MutableAggregateChange<T> {
/** Aggregate root, to which the change applies, if available */ /** Aggregate root, to which the change applies, if available */
private @Nullable T entity; private @Nullable T entity;
public DefaultAggregateChange(Kind kind, Class<T> entityType, @Nullable T entity) { /** The previous version assigned to the instance being changed, if available */
@Nullable private final Number previousVersion;
public DefaultAggregateChange(Kind kind, Class<T> entityType, @Nullable T entity, @Nullable Number previousVersion) {
this.kind = kind; this.kind = kind;
this.entityType = entityType; this.entityType = entityType;
this.entity = entity; this.entity = entity;
this.previousVersion = previousVersion;
} }
/** /**
@ -87,6 +92,12 @@ class DefaultAggregateChange<T> implements MutableAggregateChange<T> {
this.entity = aggregateRoot; this.entity = aggregateRoot;
} }
@Nullable
@Override
public Number getPreviousVersion() {
return previousVersion;
}
@Override @Override
public T getEntity() { public T getEntity() {
return this.entity; return this.entity;

37
spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MutableAggregateChange.java

@ -24,6 +24,7 @@ import org.springframework.util.ClassUtils;
* *
* @author Jens Schauder * @author Jens Schauder
* @author Mark Paluch * @author Mark Paluch
* @author Chirag Tailor
* @since 2.0 * @since 2.0
*/ */
public interface MutableAggregateChange<T> extends AggregateChange<T> { public interface MutableAggregateChange<T> extends AggregateChange<T> {
@ -36,12 +37,25 @@ public interface MutableAggregateChange<T> extends AggregateChange<T> {
* @return the {@link MutableAggregateChange} for saving the root {@code entity}. * @return the {@link MutableAggregateChange} for saving the root {@code entity}.
* @since 1.2 * @since 1.2
*/ */
@SuppressWarnings("unchecked")
static <T> MutableAggregateChange<T> forSave(T entity) { static <T> MutableAggregateChange<T> forSave(T entity) {
return forSave(entity, null);
}
/**
* Factory method to create an {@link MutableAggregateChange} for saving entities.
*
* @param entity aggregate root to save.
* @param previousVersion the previous version assigned to the instance being saved. May be {@literal null}.
* @param <T> entity type.
* @return the {@link MutableAggregateChange} for saving the root {@code entity}.
* @since 2.4
*/
@SuppressWarnings("unchecked")
static <T> MutableAggregateChange<T> forSave(T entity, @Nullable Number previousVersion) {
Assert.notNull(entity, "Entity must not be null"); Assert.notNull(entity, "Entity must not be null");
return new DefaultAggregateChange<>(Kind.SAVE, (Class<T>) ClassUtils.getUserClass(entity), entity); return new DefaultAggregateChange<>(Kind.SAVE, (Class<T>) ClassUtils.getUserClass(entity), entity, previousVersion);
} }
/** /**
@ -70,10 +84,24 @@ public interface MutableAggregateChange<T> extends AggregateChange<T> {
* @since 1.2 * @since 1.2
*/ */
static <T> MutableAggregateChange<T> forDelete(Class<T> entityClass, @Nullable T entity) { static <T> MutableAggregateChange<T> forDelete(Class<T> entityClass, @Nullable T entity) {
return forDelete(entityClass, entity, null);
}
/**
* Factory method to create an {@link MutableAggregateChange} for deleting entities.
*
* @param entityClass aggregate root type.
* @param entity aggregate root to delete.
* @param previousVersion the previous version assigned to the instance being saved. May be {@literal null}.
* @param <T> entity type.
* @return the {@link MutableAggregateChange} for deleting the root {@code entity}.
* @since 2.4
*/
static <T> MutableAggregateChange<T> forDelete(Class<T> entityClass, @Nullable T entity, @Nullable Number previousVersion) {
Assert.notNull(entityClass, "Entity class must not be null"); Assert.notNull(entityClass, "Entity class must not be null");
return new DefaultAggregateChange<>(Kind.DELETE, entityClass, entity); return new DefaultAggregateChange<>(Kind.DELETE, entityClass, entity, previousVersion);
} }
/** /**
@ -89,4 +117,7 @@ public interface MutableAggregateChange<T> extends AggregateChange<T> {
* @param aggregateRoot may be {@literal null} if the change refers to a list of aggregates or references it by id. * @param aggregateRoot may be {@literal null} if the change refers to a list of aggregates or references it by id.
*/ */
void setEntity(@Nullable T aggregateRoot); void setEntity(@Nullable T aggregateRoot);
@Nullable
Number getPreviousVersion();
} }

23
spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/RelationalEntityDeleteWriter.java

@ -37,6 +37,7 @@ import org.springframework.util.Assert;
* @author Bastian Wilhelm * @author Bastian Wilhelm
* @author Tyler Van Gorder * @author Tyler Van Gorder
* @author Myeonghyeon Lee * @author Myeonghyeon Lee
* @author Chirag Tailor
*/ */
public class RelationalEntityDeleteWriter implements EntityWriter<Object, MutableAggregateChange<?>> { public class RelationalEntityDeleteWriter implements EntityWriter<Object, MutableAggregateChange<?>> {
@ -88,7 +89,7 @@ public class RelationalEntityDeleteWriter implements EntityWriter<Object, Mutabl
return actions; return actions;
} }
private <T> List<DbAction<?>> deleteRoot(Object id, AggregateChange<T> aggregateChange) { private <T> List<DbAction<?>> deleteRoot(Object id, MutableAggregateChange<T> aggregateChange) {
List<DbAction<?>> deleteReferencedActions = deleteReferencedEntities(id, aggregateChange); List<DbAction<?>> deleteReferencedActions = deleteReferencedEntities(id, aggregateChange);
@ -98,7 +99,7 @@ public class RelationalEntityDeleteWriter implements EntityWriter<Object, Mutabl
} }
actions.addAll(deleteReferencedActions); actions.addAll(deleteReferencedActions);
actions.add(new DbAction.DeleteRoot<>(id, aggregateChange.getEntityType(), getVersion(aggregateChange))); actions.add(new DbAction.DeleteRoot<>(id, aggregateChange.getEntityType(), aggregateChange.getPreviousVersion()));
return actions; return actions;
} }
@ -121,22 +122,4 @@ public class RelationalEntityDeleteWriter implements EntityWriter<Object, Mutabl
return actions; return actions;
} }
@Nullable
private Number getVersion(AggregateChange<?> aggregateChange) {
RelationalPersistentEntity<?> persistentEntity = context
.getRequiredPersistentEntity(aggregateChange.getEntityType());
if (!persistentEntity.hasVersionProperty()) {
return null;
}
Object entity = aggregateChange.getEntity();
if (entity == null) {
return null;
}
return (Number) persistentEntity.getPropertyAccessor(entity)
.getProperty(persistentEntity.getRequiredVersionProperty());
}
} }

6
spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/WritingContext.java

@ -52,6 +52,7 @@ class WritingContext {
private final Map<PathNode, DbAction<?>> previousActions = new HashMap<>(); private final Map<PathNode, DbAction<?>> previousActions = new HashMap<>();
private final Map<PersistentPropertyPath<RelationalPersistentProperty>, List<PathNode>> nodesCache = new HashMap<>(); private final Map<PersistentPropertyPath<RelationalPersistentProperty>, List<PathNode>> nodesCache = new HashMap<>();
private final IdValueSource rootIdValueSource; private final IdValueSource rootIdValueSource;
@Nullable private final Number previousVersion;
WritingContext(RelationalMappingContext context, Object root, MutableAggregateChange<?> aggregateChange) { WritingContext(RelationalMappingContext context, Object root, MutableAggregateChange<?> aggregateChange) {
@ -59,6 +60,7 @@ class WritingContext {
this.root = root; this.root = root;
this.entity = aggregateChange.getEntity(); this.entity = aggregateChange.getEntity();
this.entityType = aggregateChange.getEntityType(); this.entityType = aggregateChange.getEntityType();
this.previousVersion = aggregateChange.getPreviousVersion();
this.rootIdValueSource = IdValueSource.forInstance(root, this.rootIdValueSource = IdValueSource.forInstance(root,
context.getRequiredPersistentEntity(aggregateChange.getEntityType())); context.getRequiredPersistentEntity(aggregateChange.getEntityType()));
this.paths = context.findPersistentPropertyPaths(entityType, (p) -> p.isEntity() && !p.isEmbedded()); this.paths = context.findPersistentPropertyPaths(entityType, (p) -> p.isEntity() && !p.isEmbedded());
@ -88,7 +90,7 @@ class WritingContext {
List<DbAction<?>> update() { List<DbAction<?>> update() {
List<DbAction<?>> actions = new ArrayList<>(); List<DbAction<?>> actions = new ArrayList<>();
actions.add(setRootAction(new DbAction.UpdateRoot<>(entity))); actions.add(setRootAction(new DbAction.UpdateRoot<>(entity, previousVersion)));
actions.addAll(deleteReferenced()); actions.addAll(deleteReferenced());
actions.addAll(insertReferenced()); actions.addAll(insertReferenced());
return actions; return actions;
@ -103,7 +105,7 @@ class WritingContext {
actions.addAll(insertReferenced()); actions.addAll(insertReferenced());
} else { } else {
actions.add(setRootAction(new DbAction.UpdateRoot<>(entity))); actions.add(setRootAction(new DbAction.UpdateRoot<>(entity, previousVersion)));
actions.addAll(deleteReferenced()); actions.addAll(deleteReferenced());
actions.addAll(insertReferenced()); actions.addAll(insertReferenced());
} }

57
spring-data-relational/src/test/java/org/springframework/data/relational/core/conversion/RelationalEntityWriterUnitTests.java

@ -85,7 +85,7 @@ public class RelationalEntityWriterUnitTests {
SingleReferenceEntity entity = new SingleReferenceEntity(null); SingleReferenceEntity entity = new SingleReferenceEntity(null);
MutableAggregateChange<SingleReferenceEntity> aggregateChange = // MutableAggregateChange<SingleReferenceEntity> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, SingleReferenceEntity.class, entity); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, SingleReferenceEntity.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -107,7 +107,7 @@ public class RelationalEntityWriterUnitTests {
PrimitiveLongIdEntity entity = new PrimitiveLongIdEntity(); PrimitiveLongIdEntity entity = new PrimitiveLongIdEntity();
MutableAggregateChange<PrimitiveLongIdEntity> aggregateChange = // MutableAggregateChange<PrimitiveLongIdEntity> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, PrimitiveLongIdEntity.class, entity); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, PrimitiveLongIdEntity.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -129,7 +129,7 @@ public class RelationalEntityWriterUnitTests {
PrimitiveIntIdEntity entity = new PrimitiveIntIdEntity(); PrimitiveIntIdEntity entity = new PrimitiveIntIdEntity();
MutableAggregateChange<PrimitiveIntIdEntity> aggregateChange = // MutableAggregateChange<PrimitiveIntIdEntity> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, PrimitiveIntIdEntity.class, entity); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, PrimitiveIntIdEntity.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -153,7 +153,7 @@ public class RelationalEntityWriterUnitTests {
entity.other = new Element(2L); entity.other = new Element(2L);
MutableAggregateChange<EmbeddedReferenceEntity> aggregateChange = // MutableAggregateChange<EmbeddedReferenceEntity> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, EmbeddedReferenceEntity.class, entity); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, EmbeddedReferenceEntity.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -177,7 +177,7 @@ public class RelationalEntityWriterUnitTests {
entity.other = new Element(null); entity.other = new Element(null);
MutableAggregateChange<SingleReferenceEntity> aggregateChange = // MutableAggregateChange<SingleReferenceEntity> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, SingleReferenceEntity.class, entity); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, SingleReferenceEntity.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -203,7 +203,7 @@ public class RelationalEntityWriterUnitTests {
entity.primitiveIntIdEntity = new PrimitiveIntIdEntity(); entity.primitiveIntIdEntity = new PrimitiveIntIdEntity();
MutableAggregateChange<EntityWithReferencesToPrimitiveIdEntity> aggregateChange = // MutableAggregateChange<EntityWithReferencesToPrimitiveIdEntity> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, EntityWithReferencesToPrimitiveIdEntity.class, entity); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, EntityWithReferencesToPrimitiveIdEntity.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -230,7 +230,7 @@ public class RelationalEntityWriterUnitTests {
SingleReferenceEntity entity = new SingleReferenceEntity(SOME_ENTITY_ID); SingleReferenceEntity entity = new SingleReferenceEntity(SOME_ENTITY_ID);
MutableAggregateChange<SingleReferenceEntity> aggregateChange = // MutableAggregateChange<SingleReferenceEntity> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, SingleReferenceEntity.class, entity); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, SingleReferenceEntity.class, entity, 1L);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -239,10 +239,11 @@ public class RelationalEntityWriterUnitTests {
DbAction::getEntityType, // DbAction::getEntityType, //
DbActionTestSupport::extractPath, // DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, // DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn) // DbActionTestSupport::isWithDependsOn, //
dbAction -> dbAction instanceof UpdateRoot ? ((UpdateRoot<?>) dbAction).getPreviousVersion() : null) //
.containsExactly( // .containsExactly( //
tuple(UpdateRoot.class, SingleReferenceEntity.class, "", SingleReferenceEntity.class, false), // tuple(UpdateRoot.class, SingleReferenceEntity.class, "", SingleReferenceEntity.class, false, 1L), //
tuple(Delete.class, Element.class, "other", null, false) // tuple(Delete.class, Element.class, "other", null, false, null) //
); );
} }
@ -253,7 +254,7 @@ public class RelationalEntityWriterUnitTests {
entity.other = new Element(null); entity.other = new Element(null);
MutableAggregateChange<SingleReferenceEntity> aggregateChange = new DefaultAggregateChange<>( MutableAggregateChange<SingleReferenceEntity> aggregateChange = new DefaultAggregateChange<>(
AggregateChange.Kind.SAVE, SingleReferenceEntity.class, entity); AggregateChange.Kind.SAVE, SingleReferenceEntity.class, entity, 1L);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -276,7 +277,7 @@ public class RelationalEntityWriterUnitTests {
SetContainer entity = new SetContainer(null); SetContainer entity = new SetContainer(null);
MutableAggregateChange<SetContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, MutableAggregateChange<SetContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE,
SetContainer.class, entity); SetContainer.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -299,7 +300,7 @@ public class RelationalEntityWriterUnitTests {
entity.elements.add(new Element(null)); entity.elements.add(new Element(null));
MutableAggregateChange<SetContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, MutableAggregateChange<SetContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE,
SetContainer.class, entity); SetContainer.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
List<DbAction<?>> actions = extractActions(aggregateChange); List<DbAction<?>> actions = extractActions(aggregateChange);
@ -342,7 +343,7 @@ public class RelationalEntityWriterUnitTests {
); );
MutableAggregateChange<CascadingReferenceEntity> aggregateChange = new DefaultAggregateChange<>( MutableAggregateChange<CascadingReferenceEntity> aggregateChange = new DefaultAggregateChange<>(
AggregateChange.Kind.SAVE, CascadingReferenceEntity.class, entity); AggregateChange.Kind.SAVE, CascadingReferenceEntity.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -404,7 +405,7 @@ public class RelationalEntityWriterUnitTests {
); );
MutableAggregateChange<CascadingReferenceEntity> aggregateChange = new DefaultAggregateChange<>( MutableAggregateChange<CascadingReferenceEntity> aggregateChange = new DefaultAggregateChange<>(
AggregateChange.Kind.SAVE, CascadingReferenceEntity.class, entity); AggregateChange.Kind.SAVE, CascadingReferenceEntity.class, entity, 1L);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -456,7 +457,7 @@ public class RelationalEntityWriterUnitTests {
MapContainer entity = new MapContainer(null); MapContainer entity = new MapContainer(null);
MutableAggregateChange<MapContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, MutableAggregateChange<MapContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE,
MapContainer.class, entity); MapContainer.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -476,7 +477,7 @@ public class RelationalEntityWriterUnitTests {
entity.elements.put("two", new Element(null)); entity.elements.put("two", new Element(null));
MutableAggregateChange<MapContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, MutableAggregateChange<MapContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE,
MapContainer.class, entity); MapContainer.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
List<DbAction<?>> actions = extractActions(aggregateChange); List<DbAction<?>> actions = extractActions(aggregateChange);
@ -520,7 +521,7 @@ public class RelationalEntityWriterUnitTests {
entity.elements.put("b", new Element(null)); entity.elements.put("b", new Element(null));
MutableAggregateChange<MapContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, MutableAggregateChange<MapContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE,
MapContainer.class, entity); MapContainer.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
List<DbAction<?>> actions = extractActions(aggregateChange); List<DbAction<?>> actions = extractActions(aggregateChange);
@ -560,7 +561,7 @@ public class RelationalEntityWriterUnitTests {
ListContainer entity = new ListContainer(null); ListContainer entity = new ListContainer(null);
MutableAggregateChange<ListContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, MutableAggregateChange<ListContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE,
ListContainer.class, entity); ListContainer.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -580,7 +581,7 @@ public class RelationalEntityWriterUnitTests {
entity.elements.add(new Element(null)); entity.elements.add(new Element(null));
MutableAggregateChange<ListContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, MutableAggregateChange<ListContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE,
ListContainer.class, entity); ListContainer.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
List<DbAction<?>> actions = extractActions(aggregateChange); List<DbAction<?>> actions = extractActions(aggregateChange);
@ -612,7 +613,7 @@ public class RelationalEntityWriterUnitTests {
entity.elements.put("one", new Element(null)); entity.elements.put("one", new Element(null));
MutableAggregateChange<MapContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, MutableAggregateChange<MapContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE,
MapContainer.class, entity); MapContainer.class, entity, 1L);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -636,7 +637,7 @@ public class RelationalEntityWriterUnitTests {
entity.elements.add(new Element(null)); entity.elements.add(new Element(null));
MutableAggregateChange<ListContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, MutableAggregateChange<ListContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE,
ListContainer.class, entity); ListContainer.class, entity, 1L);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -661,7 +662,7 @@ public class RelationalEntityWriterUnitTests {
listMapContainer.maps.get(0).elements.put("one", new Element(null)); listMapContainer.maps.get(0).elements.put("one", new Element(null));
MutableAggregateChange<ListMapContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, MutableAggregateChange<ListMapContainer> aggregateChange = new DefaultAggregateChange<>(AggregateChange.Kind.SAVE,
ListMapContainer.class, listMapContainer); ListMapContainer.class, listMapContainer, 1L);
converter.write(listMapContainer, aggregateChange); converter.write(listMapContainer, aggregateChange);
@ -689,7 +690,7 @@ public class RelationalEntityWriterUnitTests {
listMapContainer.maps.get(0).elements.put("one", new NoIdElement()); listMapContainer.maps.get(0).elements.put("one", new NoIdElement());
MutableAggregateChange<NoIdListMapContainer> aggregateChange = new DefaultAggregateChange<>( MutableAggregateChange<NoIdListMapContainer> aggregateChange = new DefaultAggregateChange<>(
AggregateChange.Kind.SAVE, NoIdListMapContainer.class, listMapContainer); AggregateChange.Kind.SAVE, NoIdListMapContainer.class, listMapContainer, 1L);
converter.write(listMapContainer, aggregateChange); converter.write(listMapContainer, aggregateChange);
@ -716,7 +717,7 @@ public class RelationalEntityWriterUnitTests {
// the embedded is null !!! // the embedded is null !!!
MutableAggregateChange<EmbeddedReferenceChainEntity> aggregateChange = // MutableAggregateChange<EmbeddedReferenceChainEntity> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, EmbeddedReferenceChainEntity.class, entity); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, EmbeddedReferenceChainEntity.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);
@ -741,7 +742,7 @@ public class RelationalEntityWriterUnitTests {
// the embedded is null !!! // the embedded is null !!!
MutableAggregateChange<RootWithEmbeddedReferenceChainEntity> aggregateChange = // MutableAggregateChange<RootWithEmbeddedReferenceChainEntity> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, RootWithEmbeddedReferenceChainEntity.class, root); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, RootWithEmbeddedReferenceChainEntity.class, root, null);
converter.write(root, aggregateChange); converter.write(root, aggregateChange);
@ -769,7 +770,7 @@ public class RelationalEntityWriterUnitTests {
root.elements.add(new Element(null)); root.elements.add(new Element(null));
root.elements.add(new Element(2L)); root.elements.add(new Element(2L));
MutableAggregateChange<ListContainer> aggregateChange = // MutableAggregateChange<ListContainer> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, ListContainer.class, root); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, ListContainer.class, root, null);
converter.write(root, aggregateChange); converter.write(root, aggregateChange);
@ -817,7 +818,7 @@ public class RelationalEntityWriterUnitTests {
entity.primitiveIntIdEntities.add(new PrimitiveIntIdEntity()); entity.primitiveIntIdEntities.add(new PrimitiveIntIdEntity());
MutableAggregateChange<EntityWithReferencesToPrimitiveIdEntity> aggregateChange = // MutableAggregateChange<EntityWithReferencesToPrimitiveIdEntity> aggregateChange = //
new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, EntityWithReferencesToPrimitiveIdEntity.class, entity); new DefaultAggregateChange<>(AggregateChange.Kind.SAVE, EntityWithReferencesToPrimitiveIdEntity.class, entity, null);
converter.write(entity, aggregateChange); converter.write(entity, aggregateChange);

Loading…
Cancel
Save