DATAJDBC-219 - Polishing.
DeleteWithVersion doesn't require an entity anymore. Added the `@author` and `@since` tags where they were missing. Formatting. Added documentation. Original pull request: #166.
This commit is contained in:
@@ -80,7 +80,6 @@ class AggregateChangeExecutor {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
private <T> T populateRootVersionIfNecessary(T newRoot, List<DbAction<?>> actions) {
|
||||
|
||||
// Does the root entity have a version attribute?
|
||||
@@ -98,12 +97,13 @@ class AggregateChangeExecutor {
|
||||
// This really should never happen.
|
||||
return newRoot;
|
||||
}
|
||||
DbAction.WithVersion<T> versionAction = (DbAction.WithVersion<T>) rootAction.get();
|
||||
DbAction.WithVersion versionAction = (DbAction.WithVersion) rootAction.get();
|
||||
|
||||
return RelationalEntityVersionUtils.setVersionNumberOnEntity(newRoot,
|
||||
versionAction.getNextVersion(), persistentEntity, converter);
|
||||
return RelationalEntityVersionUtils.setVersionNumberOnEntity(newRoot, versionAction.getNextVersion(),
|
||||
persistentEntity, converter);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
private <T> T populateIdsIfNecessary(List<DbAction<?>> actions) {
|
||||
|
||||
@@ -145,7 +145,6 @@ class AggregateChangeExecutor {
|
||||
return newRoot;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S> Object setIdAndCascadingProperties(DbAction.WithGeneratedId<S> action, @Nullable Object generatedId,
|
||||
AggregateChangeExecutor.StagedValues cascadingValues) {
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.dao.IncorrectUpdateSemanticsDataAccessException;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.conversion.DbAction;
|
||||
@@ -55,6 +56,7 @@ import org.springframework.util.Assert;
|
||||
class DefaultJdbcInterpreter implements Interpreter {
|
||||
|
||||
public static final String UPDATE_FAILED = "Failed to update entity [%s]. Id [%s] not found in database.";
|
||||
public static final String UPDATE_FAILED_OPTIMISTIC_LOCKING = "Failed to update entity [%s]. The entity was updated since it was rea or it isn't in the database at all.";
|
||||
private final RelationalConverter converter;
|
||||
private final RelationalMappingContext context;
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
@@ -65,15 +67,11 @@ class DefaultJdbcInterpreter implements Interpreter {
|
||||
*/
|
||||
@Override
|
||||
public <T> void interpret(Insert<T> insert) {
|
||||
|
||||
Object id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), getParentKeys(insert));
|
||||
insert.setGeneratedId(id);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> RelationalPersistentEntity<T> getRequiredPersistentEntity(Class<T> type) {
|
||||
return (RelationalPersistentEntity<T>) context.getRequiredPersistentEntity(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.relational.core.conversion.Interpreter#interpret(org.springframework.data.relational.core.conversion.DbAction.InsertRoot)
|
||||
@@ -83,22 +81,17 @@ class DefaultJdbcInterpreter implements Interpreter {
|
||||
|
||||
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(insert.getEntityType());
|
||||
|
||||
Object id;
|
||||
if (persistentEntity.hasVersionProperty()) {
|
||||
// The interpreter is responsible for setting the initial version on the entity prior to calling insert.
|
||||
Number version = RelationalEntityVersionUtils.getVersionNumberFromEntity(insert.getEntity(), persistentEntity,
|
||||
converter);
|
||||
if (version != null && version.longValue() > 0) {
|
||||
throw new IllegalArgumentException("The entity cannot be inserted because it already has a version.");
|
||||
}
|
||||
|
||||
T rootEntity = RelationalEntityVersionUtils.setVersionNumberOnEntity(insert.getEntity(), 1, persistentEntity,
|
||||
converter);
|
||||
Object id = accessStrategy.insert(rootEntity, insert.getEntityType(), Identifier.empty());
|
||||
id = accessStrategy.insert(rootEntity, insert.getEntityType(), Identifier.empty());
|
||||
insert.setNextVersion(1);
|
||||
insert.setGeneratedId(id);
|
||||
} else {
|
||||
Object id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), Identifier.empty());
|
||||
insert.setGeneratedId(id);
|
||||
id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), Identifier.empty());
|
||||
}
|
||||
insert.setGeneratedId(id);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -125,23 +118,25 @@ class DefaultJdbcInterpreter implements Interpreter {
|
||||
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(update.getEntityType());
|
||||
|
||||
if (persistentEntity.hasVersionProperty()) {
|
||||
|
||||
// If the root aggregate has a version property, increment it.
|
||||
Number previousVersion = RelationalEntityVersionUtils.getVersionNumberFromEntity(update.getEntity(),
|
||||
persistentEntity, converter);
|
||||
|
||||
Assert.notNull(previousVersion, "The root aggregate cannot be updated because the version property is null.");
|
||||
|
||||
T rootEntity = RelationalEntityVersionUtils.setVersionNumberOnEntity(update.getEntity(),
|
||||
previousVersion.longValue() + 1, persistentEntity,
|
||||
converter);
|
||||
previousVersion.longValue() + 1, persistentEntity, converter);
|
||||
|
||||
if (accessStrategy.updateWithVersion(rootEntity, update.getEntityType(), previousVersion)) {
|
||||
// Successful update, set the in-memory version on the action.
|
||||
update.setNextVersion(previousVersion);
|
||||
} else {
|
||||
throw new IncorrectUpdateSemanticsDataAccessException(
|
||||
String.format(UPDATE_FAILED, update.getEntity(), getIdFrom(update)));
|
||||
}
|
||||
if (accessStrategy.updateWithVersion(rootEntity, update.getEntityType(), previousVersion)) {
|
||||
// Successful update, set the in-memory version on the action.
|
||||
update.setNextVersion(previousVersion);
|
||||
} else {
|
||||
throw new OptimisticLockingFailureException(
|
||||
String.format(UPDATE_FAILED_OPTIMISTIC_LOCKING, update.getEntity()));
|
||||
}
|
||||
} else {
|
||||
|
||||
if (!accessStrategy.update(update.getEntity(), update.getEntityType())) {
|
||||
|
||||
throw new IncorrectUpdateSemanticsDataAccessException(
|
||||
@@ -179,10 +174,12 @@ class DefaultJdbcInterpreter implements Interpreter {
|
||||
@Override
|
||||
public <T> void interpret(DeleteRoot<T> delete) {
|
||||
|
||||
if (delete.getEntity() != null) {
|
||||
if (delete.getPreviousVersion() != null) {
|
||||
|
||||
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(delete.getEntityType());
|
||||
if (persistentEntity.hasVersionProperty()) {
|
||||
accessStrategy.deleteWithVersion(delete.getEntity(), delete.getEntityType());
|
||||
|
||||
accessStrategy.deleteWithVersion(delete.getId(), delete.getEntityType(), delete.getPreviousVersion());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -274,4 +271,9 @@ class DefaultJdbcInterpreter implements Interpreter {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> RelationalPersistentEntity<T> getRequiredPersistentEntity(Class<T> type) {
|
||||
return (RelationalPersistentEntity<T>) context.getRequiredPersistentEntity(type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.data.relational.domain.Identifier;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @author Tyler Van Gorder
|
||||
* @since 1.1
|
||||
*/
|
||||
public class CascadingDataAccessStrategy implements DataAccessStrategy {
|
||||
@@ -91,8 +92,8 @@ public class CascadingDataAccessStrategy implements DataAccessStrategy {
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteInstance(java.lang.Object, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> void deleteWithVersion(T instance, Class<T> domainType) {
|
||||
collectVoid(das -> das.deleteWithVersion(instance, domainType));
|
||||
public <T> void deleteWithVersion(Object id, Class<T> domainType, Number previousVersion) {
|
||||
collectVoid(das -> das.deleteWithVersion(id, domainType, previousVersion));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
@@ -75,7 +76,7 @@ public interface DataAccessStrategy extends RelationResolver {
|
||||
<T> boolean update(T instance, Class<T> domainType);
|
||||
|
||||
/**
|
||||
* Updates the data of a single entity in the database and enforce optimistic record locking using the previousVersion
|
||||
* Updates the data of a single entity in the database and enforce optimistic record locking using the {@code previousVersion}
|
||||
* property. Referenced entities don't get handled.
|
||||
* <P>
|
||||
* The statement will be of the form : {@code UPDATE … SET … WHERE ID = :id and VERSION_COLUMN = :previousVersion }
|
||||
@@ -86,6 +87,8 @@ public interface DataAccessStrategy extends RelationResolver {
|
||||
* @param previousVersion The previous version assigned to the instance being saved.
|
||||
* @param <T> the type of the instance to save.
|
||||
* @return whether the update actually updated a row.
|
||||
* @throws OptimisticLockingFailureException if the update fails to update at least one row assuming the the optimistic locking version check failed.
|
||||
* @since 2.0
|
||||
*/
|
||||
<T> boolean updateWithVersion(T instance, Class<T> domainType, Number previousVersion);
|
||||
|
||||
@@ -109,8 +112,11 @@ public interface DataAccessStrategy extends RelationResolver {
|
||||
* @param id the id of the row 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}.
|
||||
* @param previousVersion The previous version assigned to the instance being saved.
|
||||
* @throws OptimisticLockingFailureException if the update fails to update at least one row assuming the the optimistic locking version check failed.
|
||||
* @since 2.0
|
||||
*/
|
||||
<T> void deleteWithVersion(T instance, Class<T> domainType);
|
||||
<T> void deleteWithVersion(Object id, Class<T> domainType, Number previousVersion);
|
||||
|
||||
/**
|
||||
* Deletes all entities reachable via {@literal propertyPath} from the instance identified by {@literal rootId}.
|
||||
|
||||
@@ -184,23 +184,17 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteInstance(java.lang.Object, java.lang.Class)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteInstance(java.lang.Object, java.lang.Class, java.lang.Number)
|
||||
*/
|
||||
@Override
|
||||
public <T> void deleteWithVersion(T instance, Class<T> domainType) {
|
||||
public <T> void deleteWithVersion(Object id, Class<T> domainType, Number previousVersion) {
|
||||
|
||||
Assert.notNull(id, "Id must not be null.");
|
||||
|
||||
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(domainType);
|
||||
Object id = getIdValueOrNull(instance, persistentEntity);
|
||||
Assert.notNull(id, "Cannot delete an instance without it's ID being populated.");
|
||||
|
||||
if (!persistentEntity.hasVersionProperty()) {
|
||||
delete(id, domainType);
|
||||
return;
|
||||
}
|
||||
|
||||
Number oldVersion = RelationalEntityVersionUtils.getVersionNumberFromEntity(instance, persistentEntity, converter);
|
||||
MapSqlParameterSource parameterSource = createIdParameterSource(id, domainType);
|
||||
parameterSource.addValue(VERSION_SQL_PARAMETER_NAME, oldVersion);
|
||||
parameterSource.addValue(VERSION_SQL_PARAMETER_NAME, previousVersion);
|
||||
int affectedRows = operations.update(sql(domainType).getDeleteByIdAndVersion(), parameterSource);
|
||||
|
||||
if (affectedRows == 0) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.util.Assert;
|
||||
* cyclic dependencies.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Tyler Van Gorder
|
||||
* @since 1.1
|
||||
*/
|
||||
public class DelegatingDataAccessStrategy implements DataAccessStrategy {
|
||||
@@ -89,11 +90,11 @@ public class DelegatingDataAccessStrategy implements DataAccessStrategy {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteWithVersion(java.lang.Object, java.lang.Class)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteWithVersion(java.lang.Object, java.lang.Class, Number)
|
||||
*/
|
||||
@Override
|
||||
public <T> void deleteWithVersion(T instance, Class<T> domainType) {
|
||||
delegate.deleteWithVersion(instance, domainType);
|
||||
public <T> void deleteWithVersion(Object id, Class<T> domainType, Number previousVersion) {
|
||||
delegate.deleteWithVersion(id, domainType, previousVersion);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.data.relational.core.sql.Table;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @author Tyler Van Gorder
|
||||
* @since 1.1
|
||||
*/
|
||||
class SqlContext {
|
||||
@@ -43,10 +44,7 @@ class SqlContext {
|
||||
}
|
||||
|
||||
Column getVersionColumn() {
|
||||
if (!entity.hasVersionProperty()) {
|
||||
return null;
|
||||
}
|
||||
return table.column(entity.getVersionProperty().getColumnName());
|
||||
return table.column(entity.getRequiredVersionProperty().getColumnName());
|
||||
}
|
||||
|
||||
Table getTable() {
|
||||
|
||||
@@ -37,24 +37,7 @@ import org.springframework.data.relational.core.mapping.PersistentPropertyPathEx
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.AssignValue;
|
||||
import org.springframework.data.relational.core.sql.Assignments;
|
||||
import org.springframework.data.relational.core.sql.BindMarker;
|
||||
import org.springframework.data.relational.core.sql.Column;
|
||||
import org.springframework.data.relational.core.sql.Condition;
|
||||
import org.springframework.data.relational.core.sql.Delete;
|
||||
import org.springframework.data.relational.core.sql.DeleteBuilder;
|
||||
import org.springframework.data.relational.core.sql.Expression;
|
||||
import org.springframework.data.relational.core.sql.Expressions;
|
||||
import org.springframework.data.relational.core.sql.Functions;
|
||||
import org.springframework.data.relational.core.sql.Insert;
|
||||
import org.springframework.data.relational.core.sql.InsertBuilder;
|
||||
import org.springframework.data.relational.core.sql.SQL;
|
||||
import org.springframework.data.relational.core.sql.Select;
|
||||
import org.springframework.data.relational.core.sql.SelectBuilder;
|
||||
import org.springframework.data.relational.core.sql.StatementBuilder;
|
||||
import org.springframework.data.relational.core.sql.Table;
|
||||
import org.springframework.data.relational.core.sql.Update;
|
||||
import org.springframework.data.relational.core.sql.*;
|
||||
import org.springframework.data.relational.core.sql.render.SqlRenderer;
|
||||
import org.springframework.data.relational.domain.Identifier;
|
||||
import org.springframework.data.util.Lazy;
|
||||
@@ -501,25 +484,20 @@ class SqlGenerator {
|
||||
}
|
||||
|
||||
private String createUpdateSql() {
|
||||
Table table = getTable();
|
||||
|
||||
List<AssignValue> assignments = columns.getUpdateableColumns() //
|
||||
.stream() //
|
||||
.map(columnName -> Assignments.value( //
|
||||
table.column(columnName), //
|
||||
getBindMarker(columnName))) //
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Update update = Update.builder() //
|
||||
.table(table) //
|
||||
.set(assignments) //
|
||||
.where(getIdColumn().isEqualTo(getBindMarker(entity.getIdColumn()))).build();
|
||||
|
||||
return render(update);
|
||||
return render(createBaseUpdate().build());
|
||||
}
|
||||
|
||||
private String createUpdateWithVersionSql() {
|
||||
|
||||
Update update = createBaseUpdate() //
|
||||
.and(getVersionColumn().isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER_NAME))) //
|
||||
.build();
|
||||
|
||||
return render(update);
|
||||
}
|
||||
|
||||
private UpdateBuilder.UpdateWhereAndOr createBaseUpdate() {
|
||||
|
||||
Table table = getTable();
|
||||
|
||||
List<AssignValue> assignments = columns.getUpdateableColumns() //
|
||||
@@ -529,37 +507,27 @@ class SqlGenerator {
|
||||
getBindMarker(columnName))) //
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Update update = null;
|
||||
update = Update.builder() //
|
||||
return Update.builder() //
|
||||
.table(table) //
|
||||
.set(assignments) //
|
||||
.where(getIdColumn().isEqualTo(getBindMarker(entity.getIdColumn()))) //
|
||||
.and(getVersionColumn().isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER_NAME))) //
|
||||
.build();
|
||||
|
||||
return render(update);
|
||||
.where(getIdColumn().isEqualTo(getBindMarker(entity.getIdColumn())));
|
||||
}
|
||||
|
||||
private String createDeleteSql() {
|
||||
return render(createBaseDeleteById(getTable()).build());
|
||||
}
|
||||
|
||||
Table table = getTable();
|
||||
private String createDeleteByIdAndVersionSql() {
|
||||
|
||||
Delete delete = Delete.builder().from(table).where(getIdColumn().isEqualTo(SQL.bindMarker(":id"))) //
|
||||
Delete delete = createBaseDeleteById(getTable()) //
|
||||
.and(getVersionColumn().isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER_NAME))) //
|
||||
.build();
|
||||
|
||||
return render(delete);
|
||||
}
|
||||
|
||||
private String createDeleteByIdAndVersionSql() {
|
||||
Table table = getTable();
|
||||
|
||||
Delete delete = Delete.builder() //
|
||||
.from(table) //
|
||||
.where(getIdColumn().isEqualTo(SQL.bindMarker(":id"))) //
|
||||
.and(getVersionColumn().isEqualTo(SQL.bindMarker(":" + VERSION_SQL_PARAMETER_NAME))) //
|
||||
.build();
|
||||
|
||||
return render(delete);
|
||||
private DeleteBuilder.DeleteWhereAndOr createBaseDeleteById(Table table) {
|
||||
return Delete.builder().from(table).where(getIdColumn().isEqualTo(SQL.bindMarker(":id")));
|
||||
}
|
||||
|
||||
private String createDeleteByPathAndCriteria(PersistentPropertyPathExtension path,
|
||||
|
||||
@@ -174,11 +174,9 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
@Override
|
||||
public <S> boolean updateWithVersion(S instance, Class<S> domainType, Number previousVersion) {
|
||||
|
||||
Map<String, Object> additionalValues = new HashMap<>();
|
||||
additionalValues.put(VERSION_SQL_PARAMETER_NAME_OLD, previousVersion);
|
||||
|
||||
return sqlSession().update(namespace(domainType) + ".updateWithVersion",
|
||||
new MyBatisContext(null, instance, domainType, additionalValues)) != 0;
|
||||
new MyBatisContext(null, instance, domainType, Collections.singletonMap(VERSION_SQL_PARAMETER_NAME_OLD, previousVersion))) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -197,10 +195,10 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteInstance(java.lang.Object, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> void deleteWithVersion(T instance, Class<T> domainType) {
|
||||
public <T> void deleteWithVersion(Object id, Class<T> domainType, Number previousVersion) {
|
||||
|
||||
sqlSession().delete(namespace(domainType) + ".deleteWithVersion",
|
||||
new MyBatisContext(null, instance, domainType, Collections.emptyMap()));
|
||||
new MyBatisContext(id, null, domainType, Collections.singletonMap(VERSION_SQL_PARAMETER_NAME_OLD, previousVersion)));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.springframework.data.relational.domain.Identifier;
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Tyler Van Gorder
|
||||
*/
|
||||
public class DefaultJdbcInterpreterUnitTests {
|
||||
|
||||
|
||||
@@ -15,12 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.tuple;
|
||||
import static java.util.Collections.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -642,27 +638,29 @@ public class JdbcAggregateTemplateIntegrationTests {
|
||||
|
||||
@Test // DATAJDBC-219 Test that immutable version attribute works as expected.
|
||||
public void saveAndUpdateAggregateWithImmutableVersion() {
|
||||
|
||||
AggregateWithImmutableVersion aggregate = new AggregateWithImmutableVersion(null, null);
|
||||
aggregate = template.save(aggregate);
|
||||
|
||||
Long id = aggregate.getId();
|
||||
|
||||
AggregateWithImmutableVersion reloadedAggregate = template.findById(id, aggregate.getClass());
|
||||
assertThat(reloadedAggregate.getVersion()).isEqualTo(1L)
|
||||
.withFailMessage("version field should initially have the value 1");
|
||||
reloadedAggregate = template.save(reloadedAggregate);
|
||||
assertThat(reloadedAggregate.getVersion()).describedAs("version field should initially have the value 1")
|
||||
.isEqualTo(1L);
|
||||
|
||||
template.save(reloadedAggregate);
|
||||
|
||||
AggregateWithImmutableVersion updatedAggregate = template.findById(id, aggregate.getClass());
|
||||
assertThat(updatedAggregate.getVersion()).isEqualTo(2L)
|
||||
.withFailMessage("version field should increment by one with each save");
|
||||
assertThat(updatedAggregate.getVersion()).describedAs("version field should increment by one with each save")
|
||||
.isEqualTo(2L);
|
||||
|
||||
assertThatThrownBy(() -> template.save(new AggregateWithImmutableVersion(id, 1L)))
|
||||
.hasRootCauseInstanceOf(OptimisticLockingFailureException.class)
|
||||
.withFailMessage("saving an aggregate with an outdated version should raise an exception");
|
||||
.describedAs("saving an aggregate with an outdated version should raise an exception")
|
||||
.hasRootCauseInstanceOf(OptimisticLockingFailureException.class);
|
||||
|
||||
assertThatThrownBy(() -> template.save(new AggregateWithImmutableVersion(id, 3L)))
|
||||
.hasRootCauseInstanceOf(OptimisticLockingFailureException.class)
|
||||
.withFailMessage("saving an aggregate with a future version should raise an exception");
|
||||
.describedAs("saving an aggregate with a future version should raise an exception")
|
||||
.hasRootCauseInstanceOf(OptimisticLockingFailureException.class);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-219 Test that a delete with a version attribute works as expected.
|
||||
@@ -671,26 +669,26 @@ public class JdbcAggregateTemplateIntegrationTests {
|
||||
AggregateWithImmutableVersion aggregate = new AggregateWithImmutableVersion(null, null);
|
||||
aggregate = template.save(aggregate);
|
||||
|
||||
//Should have an ID and a version of 1.
|
||||
// Should have an ID and a version of 1.
|
||||
final Long id = aggregate.getId();
|
||||
|
||||
assertThatThrownBy(() -> template.delete(new AggregateWithImmutableVersion(id, 0L), AggregateWithImmutableVersion.class))
|
||||
.hasRootCauseInstanceOf(OptimisticLockingFailureException.class)
|
||||
.withFailMessage("deleting an aggregate with an outdated version should raise an exception");
|
||||
assertThatThrownBy(
|
||||
() -> template.delete(new AggregateWithImmutableVersion(id, 0L), AggregateWithImmutableVersion.class))
|
||||
.describedAs("deleting an aggregate with an outdated version should raise an exception")
|
||||
.hasRootCauseInstanceOf(OptimisticLockingFailureException.class);
|
||||
|
||||
assertThatThrownBy(() -> template.delete(new AggregateWithImmutableVersion(id, 3L), AggregateWithImmutableVersion.class))
|
||||
.hasRootCauseInstanceOf(OptimisticLockingFailureException.class)
|
||||
.withFailMessage("deleting an aggregate with a future version should raise an exception");
|
||||
assertThatThrownBy(
|
||||
() -> template.delete(new AggregateWithImmutableVersion(id, 3L), AggregateWithImmutableVersion.class))
|
||||
.describedAs("deleting an aggregate with a future version should raise an exception")
|
||||
.hasRootCauseInstanceOf(OptimisticLockingFailureException.class);
|
||||
|
||||
|
||||
//This should succeed
|
||||
// This should succeed
|
||||
template.delete(aggregate, AggregateWithImmutableVersion.class);
|
||||
|
||||
|
||||
aggregate = new AggregateWithImmutableVersion(null, null);
|
||||
aggregate = template.save(aggregate);
|
||||
|
||||
//This should succeed, as version will not be used.
|
||||
// This should succeed, as version will not be used.
|
||||
template.deleteById(aggregate.getId(), AggregateWithImmutableVersion.class);
|
||||
|
||||
}
|
||||
@@ -1013,6 +1011,7 @@ public class JdbcAggregateTemplateIntegrationTests {
|
||||
String name;
|
||||
@ReadOnlyProperty String readOnly;
|
||||
}
|
||||
|
||||
@Data
|
||||
static abstract class VersionedAggregate {
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static java.util.Collections.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -174,9 +174,9 @@ public class SqlGeneratorUnitTests {
|
||||
public void findAllByPropertyWithMultipartIdentifier() {
|
||||
|
||||
// this would get called when ListParent is the element type of a Set
|
||||
String sql = sqlGenerator.getFindAllByProperty(
|
||||
Identifier.of("backref", "some-value", String.class).withPart("backref_key", "key-value", Object.class), null,
|
||||
false);
|
||||
Identifier parentIdentifier = Identifier.of("backref", "some-value", String.class) //
|
||||
.withPart("backref_key", "key-value", Object.class);
|
||||
String sql = sqlGenerator.getFindAllByProperty(parentIdentifier, null, false);
|
||||
|
||||
assertThat(sql).contains("SELECT", //
|
||||
"dummy_entity.id1 AS id1", //
|
||||
@@ -189,7 +189,8 @@ public class SqlGeneratorUnitTests {
|
||||
"FROM dummy_entity ", //
|
||||
"LEFT OUTER JOIN referenced_entity AS ref ON ref.dummy_entity = dummy_entity.id1", //
|
||||
"LEFT OUTER JOIN second_level_referenced_entity AS ref_further ON ref_further.referenced_entity = ref.x_l1id", //
|
||||
"dummy_entity.backref = :backref", "dummy_entity.backref_key = :backref_key");
|
||||
"dummy_entity.backref = :backref", //
|
||||
"dummy_entity.backref_key = :backref_key");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-131, DATAJDBC-111
|
||||
|
||||
@@ -53,6 +53,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*
|
||||
* @author Kazuki Shimizu
|
||||
* @author Jens Schauder
|
||||
* @author Tyler Van Gorder
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@ActiveProfiles("hsql")
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.springframework.data.relational.domain.Identifier;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @author Tyler Van Gorder
|
||||
*/
|
||||
public class MyBatisDataAccessStrategyUnitTests {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user