Polishing.

Formatting.

See #1159
Original pull request # 1191
This commit is contained in:
Jens Schauder
2022-03-16 14:12:33 +01:00
parent 226bb71708
commit e019b3695a
37 changed files with 465 additions and 365 deletions

View File

@@ -31,9 +31,9 @@ import org.springframework.dao.IncorrectUpdateSemanticsDataAccessException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.Identifier;
import org.springframework.data.jdbc.core.convert.InsertSubject;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.core.convert.JdbcIdentifierBuilder;
import org.springframework.data.jdbc.core.convert.InsertSubject;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.PersistentPropertyPath;
@@ -94,7 +94,8 @@ class JdbcAggregateChangeExecutionContext {
setNewVersion(initialVersion);
} else {
id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), Identifier.empty(), insert.getIdValueSource());
id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), Identifier.empty(),
insert.getIdValueSource());
}
add(new DbActionExecutionResult(insert, id));
@@ -103,7 +104,8 @@ class JdbcAggregateChangeExecutionContext {
<T> void executeInsert(DbAction.Insert<T> insert) {
Identifier parentKeys = getParentKeys(insert, converter);
Object id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), parentKeys, insert.getIdValueSource());
Object id = accessStrategy.insert(insert.getEntity(), insert.getEntityType(), parentKeys,
insert.getIdValueSource());
add(new DbActionExecutionResult(insert, id));
}

View File

@@ -15,6 +15,13 @@
*/
package org.springframework.data.jdbc.core.convert;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.JdbcOperations;
@@ -31,21 +38,15 @@ import org.springframework.jdbc.support.KeyHolder;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Counterpart to {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations} containing
* methods for performing batch updates with generated keys.
* Counterpart to {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations} containing methods for
* performing batch updates with generated keys.
*
* @author Chirag Tailor
* @since 2.4
*/
public class BatchJdbcOperations {
private final JdbcOperations jdbcOperations;
public BatchJdbcOperations(JdbcOperations jdbcOperations) {
@@ -53,15 +54,14 @@ public class BatchJdbcOperations {
}
/**
* Execute a batch using the supplied SQL statement with the batch of supplied arguments,
* returning generated keys.
* Execute a batch using the supplied SQL statement with the batch of supplied arguments, returning generated keys.
*
* @param sql the SQL statement to execute
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of
* arguments for the query
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of arguments for the query
* @param generatedKeyHolder a {@link KeyHolder} that will hold the generated keys
* @return an array containing the numbers of rows affected by each update in the batch
* (may also contain special JDBC-defined negative values for affected rows such as
* {@link java.sql.Statement#SUCCESS_NO_INFO}/{@link java.sql.Statement#EXECUTE_FAILED})
* @return an array containing the numbers of rows affected by each update in the batch (may also contain special
* JDBC-defined negative values for affected rows such as
* {@link java.sql.Statement#SUCCESS_NO_INFO}/{@link java.sql.Statement#EXECUTE_FAILED})
* @throws org.springframework.dao.DataAccessException if there is any problem issuing the update
* @see org.springframework.jdbc.support.GeneratedKeyHolder
* @since 2.4
@@ -71,16 +71,15 @@ public class BatchJdbcOperations {
}
/**
* Execute a batch using the supplied SQL statement with the batch of supplied arguments,
* returning generated keys.
* Execute a batch using the supplied SQL statement with the batch of supplied arguments, returning generated keys.
*
* @param sql the SQL statement to execute
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of
* arguments for the query
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of arguments for the query
* @param generatedKeyHolder a {@link KeyHolder} that will hold the generated keys
* @param keyColumnNames names of the columns that will have keys generated for them
* @return an array containing the numbers of rows affected by each update in the batch
* (may also contain special JDBC-defined negative values for affected rows such as
* {@link java.sql.Statement#SUCCESS_NO_INFO}/{@link java.sql.Statement#EXECUTE_FAILED})
* @return an array containing the numbers of rows affected by each update in the batch (may also contain special
* JDBC-defined negative values for affected rows such as
* {@link java.sql.Statement#SUCCESS_NO_INFO}/{@link java.sql.Statement#EXECUTE_FAILED})
* @throws org.springframework.dao.DataAccessException if there is any problem issuing the update
* @see org.springframework.jdbc.support.GeneratedKeyHolder
* @since 2.4
@@ -91,7 +90,7 @@ public class BatchJdbcOperations {
if (batchArgs.length == 0) {
return new int[0];
}
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
SqlParameterSource paramSource = batchArgs[0];
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
@@ -105,6 +104,7 @@ public class BatchJdbcOperations {
Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null);
PreparedStatementCreator psc = pscf.newPreparedStatementCreator(params);
BatchPreparedStatementSetter bpss = new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
Object[] values = NamedParameterUtils.buildValueArray(parsedSql, batchArgs[i], null);
@@ -117,10 +117,13 @@ public class BatchJdbcOperations {
}
};
PreparedStatementCallback<int[]> preparedStatementCallback = ps -> {
int batchSize = bpss.getBatchSize();
generatedKeyHolder.getKeyList().clear();
if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
for (int i = 0; i < batchSize; i++) {
bpss.setValues(ps, i);
ps.addBatch();
}
@@ -128,8 +131,10 @@ public class BatchJdbcOperations {
storeGeneratedKeys(generatedKeyHolder, ps, batchSize);
return results;
} else {
List<Integer> rowsAffected = new ArrayList<>();
for (int i = 0; i < batchSize; i++) {
bpss.setValues(ps, i);
rowsAffected.add(ps.executeUpdate());
storeGeneratedKeys(generatedKeyHolder, ps, 1);
@@ -146,18 +151,20 @@ public class BatchJdbcOperations {
return result;
}
private void storeGeneratedKeys(KeyHolder generatedKeyHolder, PreparedStatement ps, int rowsExpected) throws SQLException {
private void storeGeneratedKeys(KeyHolder generatedKeyHolder, PreparedStatement ps, int rowsExpected)
throws SQLException {
List<Map<String, Object>> generatedKeys = generatedKeyHolder.getKeyList();
ResultSet keys = ps.getGeneratedKeys();
if (keys != null) {
try {
RowMapperResultSetExtractor<Map<String, Object>> rse =
new RowMapperResultSetExtractor<>(new ColumnMapRowMapper(), rowsExpected);
//noinspection ConstantConditions
RowMapperResultSetExtractor<Map<String, Object>> rse = new RowMapperResultSetExtractor<>(
new ColumnMapRowMapper(), rowsExpected);
// noinspection ConstantConditions
generatedKeys.addAll(rse.extractData(keys));
}
finally {
} finally {
JdbcUtils.closeResultSet(keys);
}
}

View File

@@ -76,7 +76,7 @@ public interface DataAccessStrategy extends RelationResolver {
<T> Object insert(T instance, Class<T> domainType, Identifier identifier, IdValueSource idValueSource);
/**
* Inserts the data of a multiple entities.
* Inserts the data of multiple entities.
*
* @param <T> the type of the instance.
* @param insertSubjects the subjects to be inserted, where each subject contains the instance and its identifier.

View File

@@ -79,6 +79,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, RelationalMappingContext context,
JdbcConverter converter, NamedParameterJdbcOperations operations, SqlParametersFactory sqlParametersFactory,
InsertStrategyFactory insertStrategyFactory) {
Assert.notNull(sqlGeneratorSource, "SqlGeneratorSource must not be null");
Assert.notNull(context, "RelationalMappingContext must not be null");
Assert.notNull(converter, "JdbcConverter must not be null");
@@ -104,11 +105,13 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
@Override
public <T> Object insert(T instance, Class<T> domainType, Identifier identifier, IdValueSource idValueSource) {
SqlIdentifierParameterSource parameterSource = sqlParametersFactory.forInsert(instance, domainType, identifier, idValueSource);
SqlIdentifierParameterSource parameterSource = sqlParametersFactory.forInsert(instance, domainType, identifier,
idValueSource);
String insertSql = sql(domainType).getInsert(parameterSource.getIdentifiers());
return insertStrategyFactory.insertStrategy(idValueSource, getIdColumn(domainType)).execute(insertSql, parameterSource);
return insertStrategyFactory.insertStrategy(idValueSource, getIdColumn(domainType)).execute(insertSql,
parameterSource);
}
@Override
@@ -116,12 +119,14 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
Assert.notEmpty(insertSubjects, "Batch insert must contain at least one InsertSubject");
SqlIdentifierParameterSource[] sqlParameterSources = insertSubjects.stream()
.map(insertSubject -> sqlParametersFactory.forInsert(insertSubject.getInstance(), domainType, insertSubject.getIdentifier(), idValueSource))
.map(insertSubject -> sqlParametersFactory.forInsert(insertSubject.getInstance(), domainType,
insertSubject.getIdentifier(), idValueSource))
.toArray(SqlIdentifierParameterSource[]::new);
String insertSql = sql(domainType).getInsert(sqlParameterSources[0].getIdentifiers());
return insertStrategyFactory.batchInsertStrategy(idValueSource, getIdColumn(domainType)).execute(insertSql, sqlParameterSources);
return insertStrategyFactory.batchInsertStrategy(idValueSource, getIdColumn(domainType)).execute(insertSql,
sqlParameterSources);
}
@Override
@@ -186,7 +191,8 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
String delete = sql(rootEntity.getType()).createDeleteByPath(propertyPath);
SqlIdentifierParameterSource parameters = sqlParametersFactory.forQueryById(rootId, rootEntity.getType(), ROOT_ID_PARAMETER);
SqlIdentifierParameterSource parameters = sqlParametersFactory.forQueryById(rootId, rootEntity.getType(),
ROOT_ID_PARAMETER);
operations.update(delete, parameters);
}
@@ -197,6 +203,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
@Override
public void deleteAll(PersistentPropertyPath<RelationalPersistentProperty> propertyPath) {
operations.getJdbcOperations()
.update(sql(propertyPath.getBaseProperty().getOwner().getType()).createDeleteAllSql(propertyPath));
}
@@ -338,8 +345,8 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
@Nullable
private <T> SqlIdentifier getIdColumn(Class<T> domainType) {
return Optional.ofNullable(context.getRequiredPersistentEntity(domainType).getIdProperty())
.map(RelationalPersistentProperty::getColumnName)
.orElse(null);
.map(RelationalPersistentProperty::getColumnName).orElse(null);
}
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.jdbc.core.convert;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.PersistentPropertyPath;
@@ -23,8 +25,6 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentProp
import org.springframework.data.relational.core.sql.LockMode;
import org.springframework.util.Assert;
import java.util.List;
/**
* Delegates all method calls to an instance set after construction. This is useful for {@link DataAccessStrategy}s with
* cyclic dependencies.

View File

@@ -41,9 +41,9 @@ class IdGeneratingBatchInsertStrategy implements BatchInsertStrategy {
private final BatchJdbcOperations batchJdbcOperations;
private final SqlIdentifier idColumn;
public IdGeneratingBatchInsertStrategy(InsertStrategy insertStrategy,
Dialect dialect, BatchJdbcOperations batchJdbcOperations,
@Nullable SqlIdentifier idColumn) {
IdGeneratingBatchInsertStrategy(InsertStrategy insertStrategy, Dialect dialect,
BatchJdbcOperations batchJdbcOperations, @Nullable SqlIdentifier idColumn) {
this.insertStrategy = insertStrategy;
this.dialect = dialect;
this.batchJdbcOperations = batchJdbcOperations;
@@ -54,9 +54,9 @@ class IdGeneratingBatchInsertStrategy implements BatchInsertStrategy {
public Object[] execute(String sql, SqlParameterSource[] sqlParameterSources) {
if (!dialect.getIdGeneration().supportedForBatchOperations()) {
return Arrays.stream(sqlParameterSources)
.map(sqlParameterSource -> insertStrategy.execute(sql, sqlParameterSource))
.toArray();
.map(sqlParameterSource -> insertStrategy.execute(sql, sqlParameterSource)).toArray();
}
GeneratedKeyHolder holder = new GeneratedKeyHolder();
@@ -75,6 +75,7 @@ class IdGeneratingBatchInsertStrategy implements BatchInsertStrategy {
Object[] ids = new Object[sqlParameterSources.length];
List<Map<String, Object>> keyList = holder.getKeyList();
for (int i = 0; i < keyList.size(); i++) {
Map<String, Object> keys = keyList.get(i);
if (keys.size() > 1) {
if (idColumn != null) {
@@ -92,7 +93,7 @@ class IdGeneratingBatchInsertStrategy implements BatchInsertStrategy {
private String[] getKeyColumnNames() {
return Optional.ofNullable(idColumn)
.map(idColumn -> new String[]{idColumn.getReference(dialect.getIdentifierProcessing())})
.map(idColumn -> new String[] { idColumn.getReference(dialect.getIdentifierProcessing()) })
.orElse(new String[0]);
}
}

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.data.jdbc.core.convert;
import java.util.Map;
import java.util.Optional;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.relational.core.dialect.Dialect;
@@ -26,9 +29,6 @@ import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.lang.Nullable;
import java.util.Map;
import java.util.Optional;
/**
* An {@link InsertStrategy} that expects an id to be generated from the insert.
*
@@ -41,8 +41,8 @@ class IdGeneratingInsertStrategy implements InsertStrategy {
private final NamedParameterJdbcOperations jdbcOperations;
private final SqlIdentifier idColumn;
public IdGeneratingInsertStrategy(Dialect dialect, NamedParameterJdbcOperations jdbcOperations,
@Nullable SqlIdentifier idColumn) {
IdGeneratingInsertStrategy(Dialect dialect, NamedParameterJdbcOperations jdbcOperations,
@Nullable SqlIdentifier idColumn) {
this.dialect = dialect;
this.jdbcOperations = jdbcOperations;
this.idColumn = idColumn;
@@ -68,7 +68,7 @@ class IdGeneratingInsertStrategy implements InsertStrategy {
}
try {
// MySQL just returns one value with a special name
// MySQL just returns one value with a special name
return holder.getKey();
} catch (DataRetrievalFailureException | InvalidDataAccessApiUsageException e) {
// Postgres returns a value for each column
@@ -85,7 +85,7 @@ class IdGeneratingInsertStrategy implements InsertStrategy {
private String[] getKeyColumnNames() {
return Optional.ofNullable(idColumn)
.map(idColumn -> new String[]{idColumn.getReference(dialect.getIdentifierProcessing())})
.map(idColumn -> new String[] { idColumn.getReference(dialect.getIdentifierProcessing()) })
.orElse(new String[0]);
}
}

View File

@@ -30,12 +30,14 @@ import org.springframework.lang.Nullable;
* @since 2.4
*/
public class InsertStrategyFactory {
private final NamedParameterJdbcOperations namedParameterJdbcOperations;
private final BatchJdbcOperations batchJdbcOperations;
private final Dialect dialect;
public InsertStrategyFactory(NamedParameterJdbcOperations namedParameterJdbcOperations, BatchJdbcOperations batchJdbcOperations,
Dialect dialect) {
public InsertStrategyFactory(NamedParameterJdbcOperations namedParameterJdbcOperations,
BatchJdbcOperations batchJdbcOperations, Dialect dialect) {
this.namedParameterJdbcOperations = namedParameterJdbcOperations;
this.batchJdbcOperations = batchJdbcOperations;
this.dialect = dialect;
@@ -65,8 +67,8 @@ public class InsertStrategyFactory {
if (IdValueSource.GENERATED.equals(idValueSource)) {
return new IdGeneratingBatchInsertStrategy(
new IdGeneratingInsertStrategy(dialect, namedParameterJdbcOperations, idColumn),
dialect, batchJdbcOperations, idColumn);
new IdGeneratingInsertStrategy(dialect, namedParameterJdbcOperations, idColumn), dialect, batchJdbcOperations,
idColumn);
}
return new DefaultBatchInsertStrategy(namedParameterJdbcOperations);
}
@@ -75,7 +77,7 @@ public class InsertStrategyFactory {
private final NamedParameterJdbcOperations jdbcOperations;
public DefaultInsertStrategy(NamedParameterJdbcOperations jdbcOperations) {
DefaultInsertStrategy(NamedParameterJdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}
@@ -91,7 +93,7 @@ public class InsertStrategyFactory {
private final NamedParameterJdbcOperations jdbcOperations;
public DefaultBatchInsertStrategy(NamedParameterJdbcOperations jdbcOperations) {
DefaultBatchInsertStrategy(NamedParameterJdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}

View File

@@ -27,6 +27,7 @@ import java.util.Objects;
* @since 2.4
*/
public final class InsertSubject<T> {
private final T instance;
private final Identifier identifier;
@@ -35,6 +36,7 @@ public final class InsertSubject<T> {
}
private InsertSubject(T instance, Identifier identifier) {
this.instance = instance;
this.identifier = identifier;
}
@@ -49,6 +51,7 @@ public final class InsertSubject<T> {
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())

View File

@@ -15,6 +15,11 @@
*/
package org.springframework.data.jdbc.core.convert;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository;
@@ -33,11 +38,6 @@ import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Generates SQL statements to be used by {@link SimpleJdbcRepository}
*
@@ -383,11 +383,11 @@ class SqlGenerator {
Table table = this.getTable();
Select select = StatementBuilder //
.select(getIdColumn()) //
.from(table) //
.where(getIdColumn().isEqualTo(getBindMarker(ID_SQL_PARAMETER))) //
.lock(lockMode) //
.build();
.select(getIdColumn()) //
.from(table) //
.where(getIdColumn().isEqualTo(getBindMarker(ID_SQL_PARAMETER))) //
.lock(lockMode) //
.build();
return render(select);
}
@@ -397,10 +397,10 @@ class SqlGenerator {
Table table = this.getTable();
Select select = StatementBuilder //
.select(getIdColumn()) //
.from(table) //
.lock(lockMode) //
.build();
.select(getIdColumn()) //
.from(table) //
.lock(lockMode) //
.build();
return render(select);
}
@@ -733,9 +733,9 @@ class SqlGenerator {
Join(Table joinTable, Column joinColumn, Column parentId) {
Assert.notNull( joinTable,"JoinTable must not be null.");
Assert.notNull( joinColumn,"JoinColumn must not be null.");
Assert.notNull( parentId,"ParentId must not be null.");
Assert.notNull(joinTable, "JoinTable must not be null.");
Assert.notNull(joinColumn, "JoinColumn must not be null.");
Assert.notNull(parentId, "ParentId must not be null.");
this.joinTable = joinTable;
this.joinColumn = joinColumn;
@@ -757,12 +757,12 @@ class SqlGenerator {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Join join = (Join) o;
return joinTable.equals(join.joinTable) &&
joinColumn.equals(join.joinColumn) &&
parentId.equals(join.parentId);
return joinTable.equals(join.joinTable) && joinColumn.equals(join.joinColumn) && parentId.equals(join.parentId);
}
@Override
@@ -773,11 +773,7 @@ class SqlGenerator {
@Override
public String toString() {
return "Join{" +
"joinTable=" + joinTable +
", joinColumn=" + joinColumn +
", parentId=" + parentId +
'}';
return "Join{" + "joinTable=" + joinTable + ", joinColumn=" + joinColumn + ", parentId=" + parentId + '}';
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.jdbc.core.convert;
import static org.springframework.data.jdbc.core.convert.SqlGenerator.*;
import java.sql.SQLType;
import java.util.ArrayList;
import java.util.List;
@@ -69,7 +67,8 @@ public class SqlParametersFactory {
* @return the {@link SqlIdentifierParameterSource} for the insert. Guaranteed to not be {@code null}.
* @since 2.4
*/
<T> SqlIdentifierParameterSource forInsert(T instance, Class<T> domainType, Identifier identifier, IdValueSource idValueSource) {
<T> SqlIdentifierParameterSource forInsert(T instance, Class<T> domainType, Identifier identifier,
IdValueSource idValueSource) {
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(domainType);
SqlIdentifierParameterSource parameterSource = getParameterSource(instance, persistentEntity, "",
@@ -110,9 +109,9 @@ public class SqlParametersFactory {
* @since 2.4
*/
<T> SqlIdentifierParameterSource forQueryById(Object id, Class<T> domainType, SqlIdentifier name) {
SqlIdentifierParameterSource parameterSource = new SqlIdentifierParameterSource(dialect.getIdentifierProcessing());
addConvertedPropertyValue( //
parameterSource, //
getRequiredPersistentEntity(domainType).getRequiredIdProperty(), //
@@ -135,8 +134,8 @@ public class SqlParametersFactory {
SqlIdentifierParameterSource parameterSource = new SqlIdentifierParameterSource(dialect.getIdentifierProcessing());
addConvertedPropertyValuesAsList(parameterSource, getRequiredPersistentEntity(domainType).getRequiredIdProperty(),
ids, IDS_SQL_PARAMETER);
ids);
return parameterSource;
}
@@ -150,7 +149,7 @@ public class SqlParametersFactory {
SqlIdentifierParameterSource forQueryByIdentifier(Identifier identifier) {
SqlIdentifierParameterSource parameterSource = new SqlIdentifierParameterSource(dialect.getIdentifierProcessing());
identifier.toMap()
.forEach((name, value) -> addConvertedPropertyValue(parameterSource, name, value, value.getClass()));
@@ -173,19 +172,20 @@ public class SqlParametersFactory {
}
private void addConvertedPropertyValue(SqlIdentifierParameterSource parameterSource,
RelationalPersistentProperty property, @Nullable Object value, SqlIdentifier name) {
RelationalPersistentProperty property, @Nullable Object value, SqlIdentifier name) {
addConvertedValue(parameterSource, value, name, converter.getColumnType(property), converter.getTargetSqlType(property));
addConvertedValue(parameterSource, value, name, converter.getColumnType(property),
converter.getTargetSqlType(property));
}
private void addConvertedPropertyValue(SqlIdentifierParameterSource parameterSource, SqlIdentifier name, Object value,
Class<?> javaType) {
Class<?> javaType) {
addConvertedValue(parameterSource, value, name, javaType, JdbcUtil.targetSqlTypeFor(javaType));
}
private void addConvertedValue(SqlIdentifierParameterSource parameterSource, @Nullable Object value,
SqlIdentifier paramName, Class<?> javaType, SQLType sqlType) {
SqlIdentifier paramName, Class<?> javaType, SQLType sqlType) {
JdbcValue jdbcValue = converter.writeJdbcValue( //
value, //
@@ -200,7 +200,7 @@ public class SqlParametersFactory {
}
private void addConvertedPropertyValuesAsList(SqlIdentifierParameterSource parameterSource,
RelationalPersistentProperty property, Iterable<?> values, SqlIdentifier paramName) {
RelationalPersistentProperty property, Iterable<?> values) {
List<Object> convertedIds = new ArrayList<>();
JdbcValue jdbcValue = null;
@@ -218,7 +218,7 @@ public class SqlParametersFactory {
SQLType jdbcType = jdbcValue.getJdbcType();
int typeNumber = jdbcType == null ? JdbcUtils.TYPE_UNKNOWN : jdbcType.getVendorTypeNumber();
parameterSource.addValue(paramName, convertedIds, typeNumber);
parameterSource.addValue(SqlGenerator.IDS_SQL_PARAMETER, convertedIds, typeNumber);
}
@SuppressWarnings("unchecked")
@@ -227,8 +227,8 @@ public class SqlParametersFactory {
}
private <S, T> SqlIdentifierParameterSource getParameterSource(@Nullable S instance,
RelationalPersistentEntity<S> persistentEntity, String prefix,
Predicate<RelationalPersistentProperty> skipProperty, IdentifierProcessing identifierProcessing) {
RelationalPersistentEntity<S> persistentEntity, String prefix,
Predicate<RelationalPersistentProperty> skipProperty, IdentifierProcessing identifierProcessing) {
SqlIdentifierParameterSource parameters = new SqlIdentifierParameterSource(identifierProcessing);

View File

@@ -23,10 +23,10 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@@ -101,7 +101,8 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(context, converter, dialect);
SqlParametersFactory sqlParametersFactory = new SqlParametersFactory(context, converter, dialect);
InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(operations, new BatchJdbcOperations(operations.getJdbcOperations()), dialect);
InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(operations,
new BatchJdbcOperations(operations.getJdbcOperations()), dialect);
DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy( //
sqlGeneratorSource, //
context, //
@@ -168,8 +169,8 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
@Override
public <T> Object[] insert(List<InsertSubject<T>> insertSubjects, Class<T> domainType, IdValueSource idValueSource) {
return insertSubjects.stream()
.map(insertSubject -> insert(insertSubject.getInstance(), domainType, insertSubject.getIdentifier(), idValueSource))
return insertSubjects.stream().map(
insertSubject -> insert(insertSubject.getInstance(), domainType, insertSubject.getIdentifier(), idValueSource))
.toArray();
}

View File

@@ -22,7 +22,6 @@ import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
@@ -96,8 +95,7 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware {
JdbcArrayColumns arrayColumns = dialect instanceof JdbcDialect ? ((JdbcDialect) dialect).getArraySupport()
: JdbcArrayColumns.DefaultSupport.INSTANCE;
DefaultJdbcTypeFactory jdbcTypeFactory = new DefaultJdbcTypeFactory(operations.getJdbcOperations(),
arrayColumns);
DefaultJdbcTypeFactory jdbcTypeFactory = new DefaultJdbcTypeFactory(operations.getJdbcOperations(), arrayColumns);
return new BasicJdbcConverter(mappingContext, relationResolver, conversions, jdbcTypeFactory,
dialect.getIdentifierProcessing());

View File

@@ -72,7 +72,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
JdbcConverter converter = mock(JdbcConverter.class);
DbAction.WithEntity<?> rootInsert = new DbAction.InsertRoot<>(entity, IdValueSource.GENERATED);
private DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class);
DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class);
AggregateChangeExecutor executor = new AggregateChangeExecutor(converter, accessStrategy);

View File

@@ -67,7 +67,8 @@ public class JdbcAggregateChangeExecutorContextImmutableUnitTests {
public void afterInsertRootIdAndVersionMaybeUpdated() {
// 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()), eq(IdValueSource.GENERATED))).thenReturn(23L);
when(accessStrategy.insert(any(DummyEntity.class), eq(DummyEntity.class), eq(Identifier.empty()),
eq(IdValueSource.GENERATED))).thenReturn(23L);
executionContext.executeInsertRoot(new DbAction.InsertRoot<>(root, IdValueSource.GENERATED));
@@ -86,8 +87,10 @@ public class JdbcAggregateChangeExecutorContextImmutableUnitTests {
Content content = new Content();
when(accessStrategy.insert(any(DummyEntity.class), eq(DummyEntity.class), eq(Identifier.empty()), eq(IdValueSource.GENERATED))).thenReturn(23L);
when(accessStrategy.insert(any(Content.class), eq(Content.class), eq(createBackRef()), eq(IdValueSource.GENERATED))).thenReturn(24L);
when(accessStrategy.insert(any(DummyEntity.class), eq(DummyEntity.class), eq(Identifier.empty()),
eq(IdValueSource.GENERATED))).thenReturn(23L);
when(accessStrategy.insert(any(Content.class), eq(Content.class), eq(createBackRef()), eq(IdValueSource.GENERATED)))
.thenReturn(24L);
DbAction.InsertRoot<DummyEntity> rootInsert = new DbAction.InsertRoot<>(root, IdValueSource.GENERATED);
executionContext.executeInsertRoot(rootInsert);
@@ -106,8 +109,10 @@ public class JdbcAggregateChangeExecutorContextImmutableUnitTests {
Content content = new Content();
when(accessStrategy.insert(any(DummyEntity.class), eq(DummyEntity.class), eq(Identifier.empty()), eq(IdValueSource.GENERATED))).thenReturn(23L);
when(accessStrategy.insert(eq(content), eq(Content.class), any(Identifier.class), eq(IdValueSource.GENERATED))).thenReturn(24L);
when(accessStrategy.insert(any(DummyEntity.class), eq(DummyEntity.class), eq(Identifier.empty()),
eq(IdValueSource.GENERATED))).thenReturn(23L);
when(accessStrategy.insert(eq(content), eq(Content.class), any(Identifier.class), eq(IdValueSource.GENERATED)))
.thenReturn(24L);
DbAction.InsertRoot<DummyEntity> rootInsert = new DbAction.InsertRoot<>(root, IdValueSource.GENERATED);
executionContext.executeInsertRoot(rootInsert);
@@ -124,10 +129,8 @@ public class JdbcAggregateChangeExecutorContextImmutableUnitTests {
DbAction.Insert<?> createInsert(DbAction.WithEntity<?> parent, String propertyName, Object value,
@Nullable Object key) {
DbAction.Insert<Object> insert = new DbAction.Insert<>(value, getPersistentPropertyPath(propertyName), parent,
return new DbAction.Insert<>(value, getPersistentPropertyPath(propertyName), parent,
key == null ? emptyMap() : singletonMap(toPath(propertyName), key), IdValueSource.GENERATED);
return insert;
}
PersistentPropertyPathExtension toPathExt(String path) {

View File

@@ -28,9 +28,9 @@ import org.springframework.data.annotation.Version;
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.Identifier;
import org.springframework.data.jdbc.core.convert.InsertSubject;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.core.convert.JdbcIdentifierBuilder;
import org.springframework.data.jdbc.core.convert.InsertSubject;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.PersistentPropertyPaths;
import org.springframework.data.relational.core.conversion.DbAction;
@@ -56,14 +56,13 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
});
DataAccessStrategy accessStrategy = mock(DataAccessStrategy.class);
AggregateChangeExecutor executor = new AggregateChangeExecutor(converter, accessStrategy);
JdbcAggregateChangeExecutionContext executionContext = new JdbcAggregateChangeExecutionContext(converter,
accessStrategy);
DummyEntity root = new DummyEntity();
@Test // DATAJDBC-453
public void rootOfEmptySetOfActionsisNull() {
public void rootOfEmptySetOfActionIsNull() {
Object root = executionContext.populateIdsIfNecessary();
@@ -92,7 +91,8 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
DummyEntityNonPrimitiveVersion dummyEntityNonPrimitiveVersion = new DummyEntityNonPrimitiveVersion();
executionContext.executeInsertRoot(new DbAction.InsertRoot<>(dummyEntityNonPrimitiveVersion, IdValueSource.GENERATED));
executionContext
.executeInsertRoot(new DbAction.InsertRoot<>(dummyEntityNonPrimitiveVersion, IdValueSource.GENERATED));
executionContext.populateRootVersionIfNecessary(dummyEntityNonPrimitiveVersion);
assertThat(dummyEntityNonPrimitiveVersion.version).isEqualTo(0);
@@ -124,7 +124,8 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
Content content = new Content();
when(accessStrategy.insert(root, DummyEntity.class, Identifier.empty(), IdValueSource.GENERATED)).thenReturn(23L);
when(accessStrategy.insert(eq(content), eq(Content.class), any(Identifier.class), eq(IdValueSource.GENERATED))).thenReturn(24L);
when(accessStrategy.insert(eq(content), eq(Content.class), any(Identifier.class), eq(IdValueSource.GENERATED)))
.thenReturn(24L);
DbAction.InsertRoot<DummyEntity> rootInsert = new DbAction.InsertRoot<>(root, IdValueSource.GENERATED);
executionContext.executeInsertRoot(rootInsert);
@@ -147,15 +148,12 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
executionContext.executeInsertRoot(rootInsert);
Content content = new Content();
Identifier identifier = Identifier.empty()
.withPart(SqlIdentifier.quoted("DUMMY_ENTITY"), 123L, Long.class)
Identifier identifier = Identifier.empty().withPart(SqlIdentifier.quoted("DUMMY_ENTITY"), 123L, Long.class)
.withPart(SqlIdentifier.quoted("DUMMY_ENTITY_KEY"), 0, Integer.class);
when(accessStrategy.insert(singletonList(InsertSubject.describedBy(content, identifier)), Content.class, IdValueSource.GENERATED))
.thenReturn(new Object[] { 456L });
when(accessStrategy.insert(singletonList(InsertSubject.describedBy(content, identifier)), Content.class,
IdValueSource.GENERATED)).thenReturn(new Object[] { 456L });
DbAction.InsertBatch<?> insertBatch = new DbAction.InsertBatch<>(
singletonList(createInsert(rootInsert, "list", content, 0)),
IdValueSource.GENERATED
);
singletonList(createInsert(rootInsert, "list", content, 0)), IdValueSource.GENERATED);
executionContext.executeInsertBatch(insertBatch);
DummyEntity newRoot = executionContext.populateIdsIfNecessary();
@@ -174,15 +172,12 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
executionContext.executeInsertRoot(rootInsert);
Content content = new Content();
Identifier identifier = Identifier.empty()
.withPart(SqlIdentifier.quoted("DUMMY_ENTITY"), 123L, Long.class)
Identifier identifier = Identifier.empty().withPart(SqlIdentifier.quoted("DUMMY_ENTITY"), 123L, Long.class)
.withPart(SqlIdentifier.quoted("DUMMY_ENTITY_KEY"), 0, Integer.class);
when(accessStrategy.insert(singletonList(InsertSubject.describedBy(content, identifier)), Content.class, IdValueSource.PROVIDED))
.thenReturn(new Object[] { null });
when(accessStrategy.insert(singletonList(InsertSubject.describedBy(content, identifier)), Content.class,
IdValueSource.PROVIDED)).thenReturn(new Object[] { null });
DbAction.InsertBatch<?> insertBatch = new DbAction.InsertBatch<>(
singletonList(createInsert(rootInsert, "list", content, 0)),
IdValueSource.PROVIDED
);
singletonList(createInsert(rootInsert, "list", content, 0)), IdValueSource.PROVIDED);
executionContext.executeInsertBatch(insertBatch);
DummyEntity newRoot = executionContext.populateIdsIfNecessary();
@@ -193,12 +188,10 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
}
DbAction.Insert<?> createInsert(DbAction.WithEntity<?> parent, String propertyName, Object value,
@Nullable Object key) {
@Nullable Object key) {
DbAction.Insert<Object> insert = new DbAction.Insert<>(value, getPersistentPropertyPath(propertyName), parent,
return new DbAction.Insert<>(value, getPersistentPropertyPath(propertyName), parent,
key == null ? emptyMap() : singletonMap(toPath(propertyName), key), IdValueSource.GENERATED);
return insert;
}
PersistentPropertyPathExtension toPathExt(String path) {

View File

@@ -19,6 +19,8 @@ import static java.util.Collections.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.annotation.Id;
@@ -31,8 +33,6 @@ import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import lombok.RequiredArgsConstructor;
/**
* Unit tests for {@link DefaultDataAccessStrategy}.
*
@@ -72,7 +72,7 @@ public class DefaultDataAccessStrategyUnitTests {
insertStrategyFactory);
relationResolver.setDelegate(accessStrategy);
when(sqlParametersFactory.forInsert(any(), any(), any(), any()))
.thenReturn(new SqlIdentifierParameterSource(dialect.getIdentifierProcessing()));
when(insertStrategyFactory.insertStrategy(any(), any())).thenReturn(mock(InsertStrategy.class));
@@ -90,7 +90,8 @@ public class DefaultDataAccessStrategyUnitTests {
@Test // GH-1159
public void batchInsert() {
accessStrategy.insert(singletonList(InsertSubject.describedBy(new DummyEntity(ORIGINAL_ID), Identifier.empty())), DummyEntity.class, IdValueSource.PROVIDED);
accessStrategy.insert(singletonList(InsertSubject.describedBy(new DummyEntity(ORIGINAL_ID), Identifier.empty())),
DummyEntity.class, IdValueSource.PROVIDED);
verify(insertStrategyFactory).batchInsertStrategy(IdValueSource.PROVIDED, SqlIdentifier.quoted("ID"));
}
@@ -98,7 +99,8 @@ public class DefaultDataAccessStrategyUnitTests {
@Test // GH-1159
public void insertForEntityWithNoId() {
accessStrategy.insert(new DummyEntityWithoutIdAnnotation(ORIGINAL_ID), DummyEntityWithoutIdAnnotation.class, Identifier.empty(), IdValueSource.GENERATED);
accessStrategy.insert(new DummyEntityWithoutIdAnnotation(ORIGINAL_ID), DummyEntityWithoutIdAnnotation.class,
Identifier.empty(), IdValueSource.GENERATED);
verify(insertStrategyFactory).insertStrategy(IdValueSource.GENERATED, null);
}
@@ -106,7 +108,9 @@ public class DefaultDataAccessStrategyUnitTests {
@Test // GH-1159
public void batchInsertForEntityWithNoId() {
accessStrategy.insert(singletonList(InsertSubject.describedBy(new DummyEntityWithoutIdAnnotation(ORIGINAL_ID), Identifier.empty())), DummyEntityWithoutIdAnnotation.class, IdValueSource.GENERATED);
accessStrategy.insert(
singletonList(InsertSubject.describedBy(new DummyEntityWithoutIdAnnotation(ORIGINAL_ID), Identifier.empty())),
DummyEntityWithoutIdAnnotation.class, IdValueSource.GENERATED);
verify(insertStrategyFactory).batchInsertStrategy(IdValueSource.GENERATED, null);
}

View File

@@ -22,7 +22,6 @@ import static org.mockito.Mockito.*;
import java.util.HashMap;
import org.junit.jupiter.api.Test;
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
import org.springframework.data.relational.core.dialect.AbstractDialect;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.data.relational.core.dialect.IdGeneration;
@@ -45,15 +44,14 @@ class IdGeneratingBatchInsertStrategyTest {
BatchJdbcOperations batchJdbcOperations = mock(BatchJdbcOperations.class);
InsertStrategy insertStrategy = mock(InsertStrategy.class);
String sql = "some sql";
SqlParameterSource[] sqlParameterSources = new SqlParameterSource[]{new SqlIdentifierParameterSource(identifierProcessing) };
SqlParameterSource[] sqlParameterSources = new SqlParameterSource[] {
new SqlIdentifierParameterSource(identifierProcessing) };
@Test
void insertsSequentially_whenIdGenerationForBatchOperationsNotSupported() {
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(
insertStrategy,
createDialect(identifierProcessing, true, false),
batchJdbcOperations, idColumn);
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, true, false), batchJdbcOperations, idColumn);
SqlIdentifierParameterSource sqlParameterSource1 = new SqlIdentifierParameterSource(identifierProcessing);
sqlParameterSource1.addValue(SqlIdentifier.quoted("property1"), "value1");
@@ -65,7 +63,8 @@ class IdGeneratingBatchInsertStrategyTest {
long id2 = 2L;
when(insertStrategy.execute(sql, sqlParameterSource2)).thenReturn(id2);
Object[] ids = batchInsertStrategy.execute(sql, new SqlParameterSource[]{sqlParameterSource1, sqlParameterSource2});
Object[] ids = batchInsertStrategy.execute(sql,
new SqlParameterSource[] { sqlParameterSource1, sqlParameterSource2 });
assertThat(ids).containsExactly(id1, id2);
}
@@ -73,10 +72,8 @@ class IdGeneratingBatchInsertStrategyTest {
@Test
void insertsWithKeyHolderAndKeyColumnNames_whenDriverRequiresKeyColumnNames() {
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(
insertStrategy,
createDialect(identifierProcessing, true, true),
batchJdbcOperations, idColumn);
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, true, true), batchJdbcOperations, idColumn);
batchInsertStrategy.execute(sql, sqlParameterSources);
@@ -87,10 +84,8 @@ class IdGeneratingBatchInsertStrategyTest {
@Test
void insertsWithKeyHolder_whenDriverRequiresKeyColumnNames_butIdColumnIsNull() {
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(
insertStrategy,
createDialect(identifierProcessing, true, true),
batchJdbcOperations, null);
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, true, true), batchJdbcOperations, null);
batchInsertStrategy.execute(sql, sqlParameterSources);
@@ -100,10 +95,8 @@ class IdGeneratingBatchInsertStrategyTest {
@Test
void insertsWithKeyHolder_whenDriverDoesNotRequireKeyColumnNames() {
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(
insertStrategy,
createDialect(identifierProcessing, false, true),
batchJdbcOperations, idColumn);
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, false, true), batchJdbcOperations, idColumn);
batchInsertStrategy.execute(sql, sqlParameterSources);
@@ -115,16 +108,15 @@ class IdGeneratingBatchInsertStrategyTest {
Long idValue = 123L;
when(batchJdbcOperations.batchUpdate(any(), any(), any())).thenAnswer(invocationOnMock -> {
KeyHolder keyHolder = invocationOnMock.getArgument(2);
HashMap<String, Object> keys = new HashMap<>();
keys.put("anything", idValue);
keyHolder.getKeyList().add(keys);
return null;
});
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(
insertStrategy,
createDialect(identifierProcessing, false, true),
batchJdbcOperations, idColumn);
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, false, true), batchJdbcOperations, idColumn);
Object[] ids = batchInsertStrategy.execute(sql, sqlParameterSources);
@@ -136,6 +128,7 @@ class IdGeneratingBatchInsertStrategyTest {
Long idValue = 123L;
when(batchJdbcOperations.batchUpdate(any(), any(), any())).thenAnswer(invocationOnMock -> {
KeyHolder keyHolder = invocationOnMock.getArgument(2);
HashMap<String, Object> keys = new HashMap<>();
keys.put(idColumn.getReference(), idValue);
@@ -143,10 +136,8 @@ class IdGeneratingBatchInsertStrategyTest {
keyHolder.getKeyList().add(keys);
return null;
});
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(
insertStrategy,
createDialect(identifierProcessing, false, true),
batchJdbcOperations, idColumn);
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, false, true), batchJdbcOperations, idColumn);
Object[] ids = batchInsertStrategy.execute(sql, sqlParameterSources);
@@ -158,6 +149,7 @@ class IdGeneratingBatchInsertStrategyTest {
Long idValue = 123L;
when(batchJdbcOperations.batchUpdate(any(), any(), any())).thenAnswer(invocationOnMock -> {
KeyHolder keyHolder = invocationOnMock.getArgument(2);
HashMap<String, Object> keys = new HashMap<>();
keys.put(idColumn.getReference(), idValue);
@@ -165,10 +157,8 @@ class IdGeneratingBatchInsertStrategyTest {
keyHolder.getKeyList().add(keys);
return null;
});
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(
insertStrategy,
createDialect(identifierProcessing, false, true),
batchJdbcOperations, null);
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, false, true), batchJdbcOperations, null);
Object[] ids = batchInsertStrategy.execute(sql, sqlParameterSources);
@@ -179,10 +169,8 @@ class IdGeneratingBatchInsertStrategyTest {
@Test
void insertsWithKeyHolder_returningNull_whenKeyHolderHasNoKeys() {
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(
insertStrategy,
createDialect(identifierProcessing, false, true),
batchJdbcOperations, idColumn);
BatchInsertStrategy batchInsertStrategy = new IdGeneratingBatchInsertStrategy(insertStrategy,
createDialect(identifierProcessing, false, true), batchJdbcOperations, idColumn);
Object[] ids = batchInsertStrategy.execute(sql, sqlParameterSources);
@@ -191,8 +179,7 @@ class IdGeneratingBatchInsertStrategyTest {
}
private static Dialect createDialect(final IdentifierProcessing identifierProcessing,
final boolean requiresKeyColumnNames,
final boolean supportsIdGenerationForBatchOperations) {
final boolean requiresKeyColumnNames, final boolean supportsIdGenerationForBatchOperations) {
return new AbstractDialect() {
@@ -213,7 +200,9 @@ class IdGeneratingBatchInsertStrategyTest {
@Override
public IdGeneration getIdGeneration() {
return new IdGeneration() {
@Override
public boolean driverRequiresKeyColumnNames() {
return requiresKeyColumnNames;
@@ -227,4 +216,4 @@ class IdGeneratingBatchInsertStrategyTest {
}
};
}
}
}

View File

@@ -45,7 +45,7 @@ class IdGeneratingInsertStrategyTest {
NamedParameterJdbcOperations namedParameterJdbcOperations = mock(NamedParameterJdbcOperations.class);
String sql = "some sql";
SqlParameterSource sqlParameterSource = new SqlIdentifierParameterSource(identifierProcessing);
@Test
void insertsWithKeyHolderAndKeyColumnNames_whenDriverRequiresKeyColumnNames() {
@@ -85,6 +85,7 @@ class IdGeneratingInsertStrategyTest {
Long idValue = 123L;
when(namedParameterJdbcOperations.update(any(), any(), any())).thenAnswer(invocationOnMock -> {
KeyHolder keyHolder = invocationOnMock.getArgument(2);
HashMap<String, Object> keys = new HashMap<>();
keys.put("anything", idValue);
@@ -104,6 +105,7 @@ class IdGeneratingInsertStrategyTest {
Long idValue = 123L;
when(namedParameterJdbcOperations.update(any(), any(), any())).thenAnswer(invocationOnMock -> {
KeyHolder keyHolder = invocationOnMock.getArgument(2);
HashMap<String, Object> keys = new HashMap<>();
keys.put(idColumn.getReference(), idValue);
@@ -124,6 +126,7 @@ class IdGeneratingInsertStrategyTest {
Long idValue = 123L;
when(namedParameterJdbcOperations.update(any(), any(), any())).thenAnswer(invocationOnMock -> {
KeyHolder keyHolder = invocationOnMock.getArgument(2);
HashMap<String, Object> keys = new HashMap<>();
keys.put(idColumn.getReference(), idValue);
@@ -151,7 +154,7 @@ class IdGeneratingInsertStrategyTest {
}
private static Dialect createDialect(final IdentifierProcessing identifierProcessing,
final boolean requiresKeyColumnNames) {
final boolean requiresKeyColumnNames) {
return new AbstractDialect() {
@@ -181,4 +184,4 @@ class IdGeneratingInsertStrategyTest {
}
};
}
}
}

View File

@@ -55,7 +55,8 @@ class InsertStrategyFactoryTest {
@Test
void batchInsertWithoutGeneratedIds() {
Object[] ids = insertStrategyFactory.batchInsertStrategy(IdValueSource.GENERATED, null).execute(sql, sqlParameterSources);
Object[] ids = insertStrategyFactory.batchInsertStrategy(IdValueSource.GENERATED, null).execute(sql,
sqlParameterSources);
verify(namedParameterJdbcOperations).batchUpdate(sql, sqlParameterSources);
assertThat(ids).hasSize(sqlParameterSources.length);

View File

@@ -21,6 +21,11 @@ import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategyUnitTests.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -37,11 +42,6 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.jdbc.core.JdbcOperations;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.Value;
/**
* Unit tests for {@link SqlParametersFactory}.
*
@@ -62,7 +62,8 @@ class SqlParametersFactoryTest {
singletonList(IdValueToStringConverter.INSTANCE));
String rawId = "batman";
SqlIdentifierParameterSource sqlParameterSource = sqlParametersFactory.forQueryById(new IdValue(rawId), WithValueObjectId.class, SqlGenerator.ID_SQL_PARAMETER);
SqlIdentifierParameterSource sqlParameterSource = sqlParametersFactory.forQueryById(new IdValue(rawId),
WithValueObjectId.class, SqlGenerator.ID_SQL_PARAMETER);
assertThat(sqlParameterSource.getValue("id")).isEqualTo(rawId);
}
@@ -83,7 +84,8 @@ class SqlParametersFactoryTest {
HashMap<SqlIdentifier, Object> additionalParameters = new HashMap<>();
additionalParameters.put(SqlIdentifier.quoted("DUMMYENTITYROOT"), rootIdValue);
SqlIdentifierParameterSource sqlParameterSource = sqlParametersFactory.forQueryByIdentifier(Identifier.from(additionalParameters));
SqlIdentifierParameterSource sqlParameterSource = sqlParametersFactory
.forQueryByIdentifier(Identifier.from(additionalParameters));
assertThat(sqlParameterSource.getValue("DUMMYENTITYROOT")).isEqualTo(rawId);
}
@@ -207,14 +209,14 @@ class SqlParametersFactoryTest {
@RequiredArgsConstructor
private static class DummyEntity {
@Id
private final Long id;
@Id private final Long id;
}
private SqlParametersFactory createSqlParametersFactoryWithConverters(List<?> converters) {
BasicJdbcConverter converter = new BasicJdbcConverter(context, relationResolver, new JdbcCustomConversions(converters),
new DefaultJdbcTypeFactory(mock(JdbcOperations.class)), dialect.getIdentifierProcessing());
BasicJdbcConverter converter = new BasicJdbcConverter(context, relationResolver,
new JdbcCustomConversions(converters), new DefaultJdbcTypeFactory(mock(JdbcOperations.class)),
dialect.getIdentifierProcessing());
return new SqlParametersFactory(context, converter, dialect);
}
}
}

View File

@@ -29,9 +29,7 @@ import org.mockito.ArgumentCaptor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.core.PropertyPathTestingUtils;
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
import org.springframework.data.jdbc.core.convert.Identifier;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.relational.core.conversion.IdValueSource;
@@ -50,7 +48,6 @@ import org.springframework.data.relational.core.sql.IdentifierProcessing;
public class MyBatisDataAccessStrategyUnitTests {
RelationalMappingContext context = new JdbcMappingContext();
JdbcConverter converter = new BasicJdbcConverter(context, (Identifier, path) -> null);
SqlSession session = mock(SqlSession.class);
ArgumentCaptor<MyBatisContext> captor = ArgumentCaptor.forClass(MyBatisContext.class);
@@ -69,7 +66,8 @@ public class MyBatisDataAccessStrategyUnitTests {
@Test // DATAJDBC-123
public void insert() {
accessStrategy.insert("x", String.class, Identifier.from(singletonMap(unquoted("key"), "value")), IdValueSource.GENERATED);
accessStrategy.insert("x", String.class, Identifier.from(singletonMap(unquoted("key"), "value")),
IdValueSource.GENERATED);
verify(session).insert(eq("java.lang.StringMapper.insert"), captor.capture());

View File

@@ -23,12 +23,12 @@ import static org.springframework.test.context.TestExecutionListeners.MergeMode.
import junit.framework.AssertionFailedError;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import lombok.Value;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -23,7 +23,6 @@ import java.util.Optional;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -96,12 +95,9 @@ public class TestConfiguration {
@Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template, RelationalMappingContext context,
JdbcConverter converter, Dialect dialect) {
DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy(
new SqlGeneratorSource(context, converter, dialect), context, converter, template,
new SqlParametersFactory(context, converter, dialect),
return new DefaultDataAccessStrategy(new SqlGeneratorSource(context, converter, dialect), context, converter,
template, new SqlParametersFactory(context, converter, dialect),
new InsertStrategyFactory(template, new BatchJdbcOperations(template.getJdbcOperations()), dialect));
return defaultDataAccessStrategy;
}
@Bean

View File

@@ -1,26 +1,36 @@
DROP TABLE element;
DROP TABLE dummy_entity;
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE element (id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, content VARCHAR(100), Dummy_Entity_key BIGINT, dummy_entity BIGINT);
DROP TABLE root;
DROP TABLE intermediate;
DROP TABLE leaf;
CREATE TABLE dummy_entity
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
NAME VARCHAR(100)
);
CREATE TABLE element
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY,
content VARCHAR(100),
Dummy_Entity_key BIGINT,
dummy_entity BIGINT
);
CREATE TABLE root
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY
);
CREATE TABLE intermediate
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
root BIGINT NOT NULL,
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
root BIGINT NOT NULL,
root_key INTEGER NOT NULL
);
CREATE TABLE leaf
(
name VARCHAR(100),
intermediate BIGINT NOT NULL,
name VARCHAR(100),
intermediate BIGINT NOT NULL,
intermediate_key INTEGER NOT NULL
);

View File

@@ -1,5 +1,15 @@
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE element (id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, content VARCHAR(100), Dummy_Entity_key BIGINT, dummy_entity BIGINT);
CREATE TABLE dummy_entity
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
NAME VARCHAR(100)
);
CREATE TABLE element
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY,
content VARCHAR(100),
Dummy_Entity_key BIGINT,
dummy_entity BIGINT
);
CREATE TABLE root
(
@@ -7,13 +17,13 @@ CREATE TABLE root
);
CREATE TABLE intermediate
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
root BIGINT NOT NULL,
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
root BIGINT NOT NULL,
root_key INTEGER NOT NULL
);
CREATE TABLE leaf
(
name VARCHAR(100),
intermediate BIGINT NOT NULL,
name VARCHAR(100),
intermediate BIGINT NOT NULL,
intermediate_key INTEGER NOT NULL
);

View File

@@ -1,5 +1,15 @@
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE element (id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, content VARCHAR(100), Dummy_Entity_key BIGINT, dummy_entity BIGINT);
CREATE TABLE dummy_entity
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
NAME VARCHAR(100)
);
CREATE TABLE element
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY,
content VARCHAR(100),
Dummy_Entity_key BIGINT,
dummy_entity BIGINT
);
CREATE TABLE root
(
@@ -7,13 +17,13 @@ CREATE TABLE root
);
CREATE TABLE intermediate
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
root BIGINT NOT NULL,
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
root BIGINT NOT NULL,
root_key INTEGER NOT NULL
);
CREATE TABLE leaf
(
name VARCHAR(100),
intermediate BIGINT NOT NULL,
name VARCHAR(100),
intermediate BIGINT NOT NULL,
intermediate_key INTEGER NOT NULL
);

View File

@@ -1,5 +1,15 @@
CREATE TABLE dummy_entity ( id BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE element (id BIGINT AUTO_INCREMENT PRIMARY KEY, content VARCHAR(100), Dummy_Entity_key BIGINT,dummy_entity BIGINT);
CREATE TABLE dummy_entity
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(100)
);
CREATE TABLE element
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
content VARCHAR(100),
Dummy_Entity_key BIGINT,
dummy_entity BIGINT
);
CREATE TABLE root
(
@@ -7,13 +17,13 @@ CREATE TABLE root
);
CREATE TABLE intermediate
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
root BIGINT NOT NULL,
id BIGINT AUTO_INCREMENT PRIMARY KEY,
root BIGINT NOT NULL,
root_key INTEGER NOT NULL
);
CREATE TABLE leaf
(
name VARCHAR(100),
intermediate BIGINT NOT NULL,
name VARCHAR(100),
intermediate BIGINT NOT NULL,
intermediate_key INTEGER NOT NULL
);

View File

@@ -1,24 +1,36 @@
DROP TABLE IF EXISTS dummy_entity;
DROP TABLE IF EXISTS element;
CREATE TABLE dummy_entity ( id BIGINT IDENTITY PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE element (id BIGINT IDENTITY PRIMARY KEY, content VARCHAR(100), Dummy_Entity_key BIGINT,dummy_entity BIGINT);
DROP TABLE IF EXISTS root;
DROP TABLE IF EXISTS intermediate;
DROP TABLE IF EXISTS leaf;
CREATE TABLE dummy_entity
(
id BIGINT IDENTITY PRIMARY KEY,
NAME VARCHAR(100)
);
CREATE TABLE element
(
id BIGINT IDENTITY PRIMARY KEY,
content VARCHAR(100),
Dummy_Entity_key BIGINT,
dummy_entity BIGINT
);
CREATE TABLE root
(
id BIGINT IDENTITY PRIMARY KEY
);
CREATE TABLE intermediate
(
id BIGINT IDENTITY PRIMARY KEY,
root BIGINT NOT NULL,
id BIGINT IDENTITY PRIMARY KEY,
root BIGINT NOT NULL,
root_key INTEGER NOT NULL
);
CREATE TABLE leaf
(
name VARCHAR(100),
intermediate BIGINT NOT NULL,
name VARCHAR(100),
intermediate BIGINT NOT NULL,
intermediate_key INTEGER NOT NULL
);

View File

@@ -1,5 +1,15 @@
CREATE TABLE dummy_entity ( id BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE element (id BIGINT AUTO_INCREMENT PRIMARY KEY, content VARCHAR(100), Dummy_Entity_key BIGINT,dummy_entity BIGINT);
CREATE TABLE dummy_entity
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(100)
);
CREATE TABLE element
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
content VARCHAR(100),
Dummy_Entity_key BIGINT,
dummy_entity BIGINT
);
CREATE TABLE root
(
@@ -7,13 +17,13 @@ CREATE TABLE root
);
CREATE TABLE intermediate
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
root BIGINT NOT NULL,
id BIGINT AUTO_INCREMENT PRIMARY KEY,
root BIGINT NOT NULL,
root_key INTEGER NOT NULL
);
CREATE TABLE leaf
(
name VARCHAR(100),
intermediate BIGINT NOT NULL,
name VARCHAR(100),
intermediate BIGINT NOT NULL,
intermediate_key INTEGER NOT NULL
);

View File

@@ -1,35 +1,37 @@
DROP TABLE ELEMENT;
DROP TABLE DUMMY_ENTITY;
CREATE TABLE DUMMY_ENTITY (
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
NAME VARCHAR2(100)
);
CREATE TABLE ELEMENT (
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
CONTENT VARCHAR(100),
DUMMY_ENTITY_KEY NUMBER,
DUMMY_ENTITY NUMBER
);
DROP TABLE root;
DROP TABLE intermediate;
DROP TABLE leaf;
CREATE TABLE DUMMY_ENTITY
(
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
NAME VARCHAR2(100)
);
CREATE TABLE ELEMENT
(
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
CONTENT VARCHAR(100),
DUMMY_ENTITY_KEY NUMBER,
DUMMY_ENTITY NUMBER
);
CREATE TABLE root
(
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY
);
CREATE TABLE intermediate
(
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
root NUMBER NOT NULL,
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
root NUMBER NOT NULL,
root_key NUMBER NOT NULL
);
CREATE TABLE leaf
(
name VARCHAR(100),
intermediate NUMBER NOT NULL,
name VARCHAR(100),
intermediate NUMBER NOT NULL,
intermediate_key NUMBER NOT NULL
);

View File

@@ -1,24 +1,36 @@
DROP TABLE element;
DROP TABLE dummy_entity;
CREATE TABLE dummy_entity ( id SERIAL PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE element (id SERIAL PRIMARY KEY, content VARCHAR(100),dummy_entity_key BIGINT, dummy_entity BIGINT);
DROP TABLE root;
DROP TABLE intermediate;
DROP TABLE leaf;
CREATE TABLE dummy_entity
(
id SERIAL PRIMARY KEY,
NAME VARCHAR(100)
);
CREATE TABLE element
(
id SERIAL PRIMARY KEY,
content VARCHAR(100),
dummy_entity_key BIGINT,
dummy_entity BIGINT
);
CREATE TABLE root
(
id SERIAL PRIMARY KEY
);
CREATE TABLE intermediate
(
id SERIAL PRIMARY KEY,
root BIGINT NOT NULL,
id SERIAL PRIMARY KEY,
root BIGINT NOT NULL,
root_key INTEGER NOT NULL
);
CREATE TABLE leaf
(
name VARCHAR(100),
intermediate BIGINT NOT NULL,
name VARCHAR(100),
intermediate BIGINT NOT NULL,
intermediate_key INTEGER NOT NULL
);

View File

@@ -110,6 +110,7 @@ public interface DbAction<T> {
private final IdValueSource idValueSource;
public InsertRoot(T entity, IdValueSource idValueSource) {
this.entity = entity;
this.idValueSource = idValueSource;
}

View File

@@ -17,7 +17,11 @@ package org.springframework.data.relational.core.conversion;
import static java.util.Arrays.*;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.data.mapping.PersistentPropertyPath;
@@ -55,7 +59,8 @@ class WritingContext {
this.root = root;
this.entity = aggregateChange.getEntity();
this.entityType = aggregateChange.getEntityType();
this.rootIdValueSource = IdValueSource.forInstance(root, context.getRequiredPersistentEntity(aggregateChange.getEntityType()));
this.rootIdValueSource = IdValueSource.forInstance(root,
context.getRequiredPersistentEntity(aggregateChange.getEntityType()));
this.paths = context.findPersistentPropertyPaths(entityType, (p) -> p.isEntity() && !p.isEmbedded());
}
@@ -124,7 +129,8 @@ class WritingContext {
@SuppressWarnings("unchecked")
private List<? extends DbAction<?>> insertAll(PersistentPropertyPath<RelationalPersistentProperty> path) {
RelationalPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(path.getRequiredLeafProperty());
RelationalPersistentEntity<?> persistentEntity = context
.getRequiredPersistentEntity(path.getRequiredLeafProperty());
List<DbAction.Insert<Object>> inserts = new ArrayList<>();
from(path).forEach(node -> {
@@ -150,18 +156,15 @@ class WritingContext {
inserts.add(insert);
previousActions.put(node, insert);
});
return inserts.stream()
.collect(Collectors.groupingBy(DbAction.Insert::getIdValueSource))
.entrySet().stream()
.filter(entry -> (!entry.getValue().isEmpty()))
.map(entry -> {
return inserts.stream().collect(Collectors.groupingBy(DbAction.Insert::getIdValueSource)).entrySet().stream()
.filter(entry -> (!entry.getValue().isEmpty())).map(entry -> {
List<DbAction.Insert<Object>> batch = entry.getValue();
if (batch.size() > 1) {
return new DbAction.InsertBatch<>(batch, entry.getKey());
}
return batch.get(0);
})
.collect(Collectors.toList());
}).collect(Collectors.toList());
}
private List<DbAction<?>> deleteReferenced() {

View File

@@ -37,6 +37,7 @@ public class SqlServerDialect extends AbstractDialect {
public static final SqlServerDialect INSTANCE = new SqlServerDialect();
private static final IdGeneration ID_GENERATION = new IdGeneration() {
@Override
public boolean supportedForBatchOperations() {
return false;

View File

@@ -16,10 +16,12 @@
package org.springframework.data.relational.core.conversion;
import lombok.experimental.UtilityClass;
import org.springframework.lang.Nullable;
/**
* Utility class for analyzing DbActions in tests.
*
* @author Jens Schauder
* @author Chirag Tailor
*/
@@ -49,6 +51,7 @@ class DbActionTestSupport {
@Nullable
static IdValueSource insertIdValueSource(DbAction<?> action) {
if (action instanceof DbAction.InsertRoot) {
return ((DbAction.InsertRoot<?>) action).getIdValueSource();
} else if (action instanceof DbAction.Insert) {

View File

@@ -17,6 +17,9 @@ package org.springframework.data.relational.core.conversion;
import static org.assertj.core.api.Assertions.*;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -43,9 +46,6 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.lang.Nullable;
import lombok.Data;
import lombok.RequiredArgsConstructor;
/**
* Unit tests for the {@link RelationalEntityWriter}
*
@@ -97,7 +97,8 @@ public class RelationalEntityWriterUnitTests {
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(InsertRoot.class, SingleReferenceEntity.class, "", SingleReferenceEntity.class, false, IdValueSource.GENERATED) //
tuple(InsertRoot.class, SingleReferenceEntity.class, "", SingleReferenceEntity.class, false,
IdValueSource.GENERATED) //
);
}
@@ -118,7 +119,8 @@ public class RelationalEntityWriterUnitTests {
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(InsertRoot.class, PrimitiveLongIdEntity.class, "", PrimitiveLongIdEntity.class, false, IdValueSource.GENERATED) //
tuple(InsertRoot.class, PrimitiveLongIdEntity.class, "", PrimitiveLongIdEntity.class, false,
IdValueSource.GENERATED) //
);
}
@@ -139,7 +141,8 @@ public class RelationalEntityWriterUnitTests {
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(InsertRoot.class, PrimitiveIntIdEntity.class, "", PrimitiveIntIdEntity.class, false, IdValueSource.GENERATED) //
tuple(InsertRoot.class, PrimitiveIntIdEntity.class, "", PrimitiveIntIdEntity.class, false,
IdValueSource.GENERATED) //
);
}
@@ -162,7 +165,8 @@ public class RelationalEntityWriterUnitTests {
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(InsertRoot.class, EmbeddedReferenceEntity.class, "", EmbeddedReferenceEntity.class, false, IdValueSource.GENERATED) //
tuple(InsertRoot.class, EmbeddedReferenceEntity.class, "", EmbeddedReferenceEntity.class, false,
IdValueSource.GENERATED) //
);
}
@@ -185,7 +189,8 @@ public class RelationalEntityWriterUnitTests {
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(InsertRoot.class, SingleReferenceEntity.class, "", SingleReferenceEntity.class, false, IdValueSource.GENERATED), //
tuple(InsertRoot.class, SingleReferenceEntity.class, "", SingleReferenceEntity.class, false,
IdValueSource.GENERATED), //
tuple(Insert.class, Element.class, "other", Element.class, true, IdValueSource.GENERATED) //
);
}
@@ -210,9 +215,12 @@ public class RelationalEntityWriterUnitTests {
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactlyInAnyOrder( //
tuple(InsertRoot.class, EntityWithReferencesToPrimitiveIdEntity.class, "", EntityWithReferencesToPrimitiveIdEntity.class, false, IdValueSource.GENERATED), //
tuple(Insert.class, PrimitiveLongIdEntity.class, "primitiveLongIdEntity", PrimitiveLongIdEntity.class, true, IdValueSource.GENERATED), //
tuple(Insert.class, PrimitiveIntIdEntity.class, "primitiveIntIdEntity", PrimitiveIntIdEntity.class, true, IdValueSource.GENERATED) //
tuple(InsertRoot.class, EntityWithReferencesToPrimitiveIdEntity.class, "",
EntityWithReferencesToPrimitiveIdEntity.class, false, IdValueSource.GENERATED), //
tuple(Insert.class, PrimitiveLongIdEntity.class, "primitiveLongIdEntity", PrimitiveLongIdEntity.class, true,
IdValueSource.GENERATED), //
tuple(Insert.class, PrimitiveIntIdEntity.class, "primitiveIntIdEntity", PrimitiveIntIdEntity.class, true,
IdValueSource.GENERATED) //
);
}
@@ -307,11 +315,11 @@ public class RelationalEntityWriterUnitTests {
);
List<Insert<Element>> batchedInsertActions = getInsertBatchAction(actions, Element.class).getInserts();
assertThat(batchedInsertActions).extracting(DbAction::getClass, //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(Insert.class, Element.class, "elements", Element.class, true, IdValueSource.GENERATED), //
tuple(Insert.class, Element.class, "elements", Element.class, true, IdValueSource.GENERATED) //
@@ -346,17 +354,19 @@ public class RelationalEntityWriterUnitTests {
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(InsertRoot.class, CascadingReferenceEntity.class, "", CascadingReferenceEntity.class, false, IdValueSource.GENERATED), //
tuple(InsertRoot.class, CascadingReferenceEntity.class, "", CascadingReferenceEntity.class, false,
IdValueSource.GENERATED), //
tuple(InsertBatch.class, CascadingReferenceMiddleElement.class, "", null, false, IdValueSource.GENERATED), //
tuple(InsertBatch.class, Element.class, "", null, false, IdValueSource.GENERATED) //
);
List<Insert<CascadingReferenceMiddleElement>> middleElementInserts = getInsertBatchAction(actions, CascadingReferenceMiddleElement.class).getInserts();
List<Insert<CascadingReferenceMiddleElement>> middleElementInserts = getInsertBatchAction(actions,
CascadingReferenceMiddleElement.class).getInserts();
assertThat(middleElementInserts).extracting(DbAction::getClass, //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(Insert.class, CascadingReferenceMiddleElement.class, "other", CascadingReferenceMiddleElement.class,
true, IdValueSource.GENERATED), //
@@ -365,11 +375,11 @@ public class RelationalEntityWriterUnitTests {
);
List<Insert<Element>> leafElementInserts = getInsertBatchAction(actions, Element.class).getInserts();
assertThat(leafElementInserts).extracting(DbAction::getClass, //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(Insert.class, Element.class, "other.element", Element.class, true, IdValueSource.GENERATED), //
tuple(Insert.class, Element.class, "other.element", Element.class, true, IdValueSource.GENERATED), //
@@ -415,11 +425,11 @@ public class RelationalEntityWriterUnitTests {
List<Insert<CascadingReferenceMiddleElement>> middleElementInserts = getInsertBatchAction(actions,
CascadingReferenceMiddleElement.class).getInserts();
assertThat(middleElementInserts).extracting(DbAction::getClass, //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(Insert.class, CascadingReferenceMiddleElement.class, "other", CascadingReferenceMiddleElement.class,
true, IdValueSource.GENERATED), //
@@ -428,11 +438,11 @@ public class RelationalEntityWriterUnitTests {
);
List<Insert<Element>> elementInserts = getInsertBatchAction(actions, Element.class).getInserts();
assertThat(elementInserts).extracting(DbAction::getClass, //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(Insert.class, Element.class, "other.element", Element.class, true, IdValueSource.GENERATED), //
tuple(Insert.class, Element.class, "other.element", Element.class, true, IdValueSource.GENERATED), //
@@ -481,10 +491,10 @@ public class RelationalEntityWriterUnitTests {
);
List<Insert<Element>> inserts = getInsertBatchAction(actions, Element.class).getInserts();
assertThat(inserts).extracting(DbAction::getClass, //
DbAction::getEntityType, //
this::getMapKey, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
this::getMapKey, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::insertIdValueSource) //
.containsExactlyInAnyOrder( //
tuple(Insert.class, Element.class, "one", "elements", IdValueSource.GENERATED), //
tuple(Insert.class, Element.class, "two", "elements", IdValueSource.GENERATED) //
@@ -525,10 +535,10 @@ public class RelationalEntityWriterUnitTests {
);
List<Insert<Element>> inserts = getInsertBatchAction(actions, Element.class).getInserts();
assertThat(inserts).extracting(DbAction::getClass, //
DbAction::getEntityType, //
this::getMapKey, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
this::getMapKey, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::insertIdValueSource) //
.containsExactlyInAnyOrder( //
tuple(Insert.class, Element.class, "1", "elements", IdValueSource.GENERATED), //
tuple(Insert.class, Element.class, "2", "elements", IdValueSource.GENERATED), //
@@ -718,7 +728,8 @@ public class RelationalEntityWriterUnitTests {
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(InsertRoot.class, EmbeddedReferenceChainEntity.class, "", EmbeddedReferenceChainEntity.class, false, IdValueSource.GENERATED) //
tuple(InsertRoot.class, EmbeddedReferenceChainEntity.class, "", EmbeddedReferenceChainEntity.class, false,
IdValueSource.GENERATED) //
);
}
@@ -764,35 +775,34 @@ public class RelationalEntityWriterUnitTests {
List<DbAction<?>> actions = extractActions(aggregateChange);
assertThat(actions).extracting(DbAction::getClass, //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsSubsequence(
tuple(InsertRoot.class, ListContainer.class, "", ListContainer.class, false, IdValueSource.GENERATED), //
tuple(InsertBatch.class, Element.class, "", null, false, IdValueSource.PROVIDED) //
)
.containsSubsequence( //
).containsSubsequence( //
tuple(InsertRoot.class, ListContainer.class, "", ListContainer.class, false, IdValueSource.GENERATED), //
tuple(InsertBatch.class, Element.class, "", null, false, IdValueSource.GENERATED) //
);
InsertBatch<Element> insertBatchWithoutId = getInsertBatchAction(actions, Element.class, IdValueSource.GENERATED);
assertThat(insertBatchWithoutId.getInserts()).extracting(DbAction::getClass, //
DbAction::getEntityType, //
this::getListKey, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
this::getListKey, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(Insert.class, Element.class, 0, "elements", IdValueSource.GENERATED), //
tuple(Insert.class, Element.class, 2, "elements", IdValueSource.GENERATED) //
);
InsertBatch<Element> insertBatchWithId = getInsertBatchAction(actions, Element.class, IdValueSource.PROVIDED);
assertThat(insertBatchWithId.getInserts()).extracting(DbAction::getClass, //
DbAction::getEntityType, //
this::getListKey, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
this::getListKey, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::insertIdValueSource) //
.containsExactly( //
tuple(Insert.class, Element.class, 1, "elements", IdValueSource.PROVIDED), //
tuple(Insert.class, Element.class, 3, "elements", IdValueSource.PROVIDED) //
@@ -813,15 +823,18 @@ public class RelationalEntityWriterUnitTests {
List<DbAction<?>> actions = extractActions(aggregateChange);
assertThat(actions).extracting(DbAction::getClass, //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
DbAction::getEntityType, //
DbActionTestSupport::extractPath, //
DbActionTestSupport::actualEntityType, //
DbActionTestSupport::isWithDependsOn, //
DbActionTestSupport::insertIdValueSource) //
.containsExactlyInAnyOrder( //
tuple(InsertRoot.class, EntityWithReferencesToPrimitiveIdEntity.class, "", EntityWithReferencesToPrimitiveIdEntity.class, false, IdValueSource.GENERATED), //
tuple(Insert.class, PrimitiveLongIdEntity.class, "primitiveLongIdEntities", PrimitiveLongIdEntity.class, true, IdValueSource.GENERATED), //
tuple(Insert.class, PrimitiveIntIdEntity.class, "primitiveIntIdEntities", PrimitiveIntIdEntity.class, true, IdValueSource.GENERATED) //
tuple(InsertRoot.class, EntityWithReferencesToPrimitiveIdEntity.class, "",
EntityWithReferencesToPrimitiveIdEntity.class, false, IdValueSource.GENERATED), //
tuple(Insert.class, PrimitiveLongIdEntity.class, "primitiveLongIdEntities", PrimitiveLongIdEntity.class,
true, IdValueSource.GENERATED), //
tuple(Insert.class, PrimitiveIntIdEntity.class, "primitiveIntIdEntities", PrimitiveIntIdEntity.class, true,
IdValueSource.GENERATED) //
);
}
@@ -834,28 +847,25 @@ public class RelationalEntityWriterUnitTests {
@NotNull
private <T> InsertBatch<T> getInsertBatchAction(List<DbAction<?>> actions, Class<T> entityType) {
return getInsertBatchActions(actions, entityType).stream()
.findFirst()
return getInsertBatchActions(actions, entityType).stream().findFirst()
.orElseThrow(() -> new RuntimeException("No InsertBatch action found!"));
}
@NotNull
private <T> InsertBatch<T> getInsertBatchAction(List<DbAction<?>> actions, Class<T> entityType,
IdValueSource idValueSource) {
IdValueSource idValueSource) {
return getInsertBatchActions(actions, entityType).stream()
.filter(insertBatch -> insertBatch.getIdValueSource() == idValueSource)
.findFirst()
.orElseThrow(() -> new RuntimeException(String.format("No InsertBatch with includeId '%s' found!", idValueSource)));
.filter(insertBatch -> insertBatch.getIdValueSource() == idValueSource).findFirst().orElseThrow(
() -> new RuntimeException(String.format("No InsertBatch with includeId '%s' found!", idValueSource)));
}
@NotNull
private <T> List<InsertBatch<T>> getInsertBatchActions(List<DbAction<?>> actions, Class<T> entityType) {
//noinspection unchecked
// noinspection unchecked
return actions.stream() //
.filter(dbAction -> dbAction instanceof InsertBatch) //
.filter(dbAction -> dbAction.getEntityType().equals(entityType)) //
.map(dbAction -> (InsertBatch<T>) dbAction)
.collect(Collectors.toList());
.map(dbAction -> (InsertBatch<T>) dbAction).collect(Collectors.toList());
}
private CascadingReferenceMiddleElement createMiddleElement(Element first, Element second) {