@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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 + '}';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
@@ -110,6 +110,7 @@ public interface DbAction<T> {
|
||||
private final IdValueSource idValueSource;
|
||||
|
||||
public InsertRoot(T entity, IdValueSource idValueSource) {
|
||||
|
||||
this.entity = entity;
|
||||
this.idValueSource = idValueSource;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user