Skip to content

Add support for composite ids #1957

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: 4.0.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pipeline {

triggers {
pollSCM 'H/10 * * * *'
upstream(upstreamProjects: "spring-data-commons/main", threshold: hudson.model.Result.SUCCESS)
upstream(upstreamProjects: "spring-data-commons/4.0.x", threshold: hudson.model.Result.SUCCESS)
}

options {
Expand Down
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>4.0.0-1737-nullable-embedded-with-collection-574-composite-id-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data Relational Parent</name>
Expand All @@ -15,12 +15,12 @@
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>4.0.0-SNAPSHOT</version>
</parent>

<properties>
<dist.id>spring-data-jdbc</dist.id>
<springdata.commons>3.5.0-SNAPSHOT</springdata.commons>
<springdata.commons>4.0.0-SNAPSHOT</springdata.commons>
<liquibase.version>4.21.1</liquibase.version>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-jdbc-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>4.0.0-1737-nullable-embedded-with-collection-574-composite-id-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
4 changes: 2 additions & 2 deletions spring-data-jdbc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-data-jdbc</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>4.0.0-1737-nullable-embedded-with-collection-574-composite-id-SNAPSHOT</version>

<name>Spring Data JDBC</name>
<description>Spring Data module for JDBC repositories.</description>
Expand All @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>3.5.0-SNAPSHOT</version>
<version>4.0.0-1737-nullable-embedded-with-collection-574-composite-id-SNAPSHOT</version>
</parent>

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,21 @@
*/
package org.springframework.data.jdbc.core;

import org.springframework.dao.OptimisticLockingFailureException;
import java.util.List;

import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.relational.core.conversion.AggregateChange;
import org.springframework.data.relational.core.conversion.DbAction;
import org.springframework.data.relational.core.conversion.DbActionExecutionException;
import org.springframework.data.relational.core.conversion.MutableAggregateChange;

import java.util.List;

/**
* Executes an {@link MutableAggregateChange}.
*
* @author Jens Schauder
* @author Myeonghyeon Lee
* @author Chirag Tailor
* @author Mikhail Polivakha
* @since 2.0
*/
class AggregateChangeExecutor {
Expand Down Expand Up @@ -80,42 +79,34 @@ <T> void executeDelete(AggregateChange<T> aggregateChange) {

private void execute(DbAction<?> action, JdbcAggregateChangeExecutionContext executionContext) {

try {
if (action instanceof DbAction.InsertRoot<?> insertRoot) {
executionContext.executeInsertRoot(insertRoot);
} else if (action instanceof DbAction.BatchInsertRoot<?> batchInsertRoot) {
executionContext.executeBatchInsertRoot(batchInsertRoot);
} else if (action instanceof DbAction.Insert<?> insert) {
executionContext.executeInsert(insert);
} else if (action instanceof DbAction.BatchInsert<?> batchInsert) {
executionContext.executeBatchInsert(batchInsert);
} else if (action instanceof DbAction.UpdateRoot<?> updateRoot) {
executionContext.executeUpdateRoot(updateRoot);
} else if (action instanceof DbAction.Delete<?> delete) {
executionContext.executeDelete(delete);
} else if (action instanceof DbAction.BatchDelete<?> batchDelete) {
executionContext.executeBatchDelete(batchDelete);
} else if (action instanceof DbAction.DeleteAll<?> deleteAll) {
executionContext.executeDeleteAll(deleteAll);
} else if (action instanceof DbAction.DeleteRoot<?> deleteRoot) {
executionContext.executeDeleteRoot(deleteRoot);
} else if (action instanceof DbAction.BatchDeleteRoot<?> batchDeleteRoot) {
executionContext.executeBatchDeleteRoot(batchDeleteRoot);
} else if (action instanceof DbAction.DeleteAllRoot<?> deleteAllRoot) {
executionContext.executeDeleteAllRoot(deleteAllRoot);
} else if (action instanceof DbAction.AcquireLockRoot<?> acquireLockRoot) {
executionContext.executeAcquireLock(acquireLockRoot);
} else if (action instanceof DbAction.AcquireLockAllRoot<?> acquireLockAllRoot) {
executionContext.executeAcquireLockAllRoot(acquireLockAllRoot);
} else {
throw new RuntimeException("unexpected action");
}
} catch (Exception e) {

if (e instanceof OptimisticLockingFailureException) {
throw e;
}
throw new DbActionExecutionException(action, e);
if (action instanceof DbAction.InsertRoot<?> insertRoot) {
executionContext.executeInsertRoot(insertRoot);
} else if (action instanceof DbAction.BatchInsertRoot<?> batchInsertRoot) {
executionContext.executeBatchInsertRoot(batchInsertRoot);
} else if (action instanceof DbAction.Insert<?> insert) {
executionContext.executeInsert(insert);
} else if (action instanceof DbAction.BatchInsert<?> batchInsert) {
executionContext.executeBatchInsert(batchInsert);
} else if (action instanceof DbAction.UpdateRoot<?> updateRoot) {
executionContext.executeUpdateRoot(updateRoot);
} else if (action instanceof DbAction.Delete<?> delete) {
executionContext.executeDelete(delete);
} else if (action instanceof DbAction.BatchDelete<?> batchDelete) {
executionContext.executeBatchDelete(batchDelete);
} else if (action instanceof DbAction.DeleteAll<?> deleteAll) {
executionContext.executeDeleteAll(deleteAll);
} else if (action instanceof DbAction.DeleteRoot<?> deleteRoot) {
executionContext.executeDeleteRoot(deleteRoot);
} else if (action instanceof DbAction.BatchDeleteRoot<?> batchDeleteRoot) {
executionContext.executeBatchDeleteRoot(batchDeleteRoot);
} else if (action instanceof DbAction.DeleteAllRoot<?> deleteAllRoot) {
executionContext.executeDeleteAllRoot(deleteAllRoot);
} else if (action instanceof DbAction.AcquireLockRoot<?> acquireLockRoot) {
executionContext.executeAcquireLock(acquireLockRoot);
} else if (action instanceof DbAction.AcquireLockAllRoot<?> acquireLockAllRoot) {
executionContext.executeAcquireLockAllRoot(acquireLockAllRoot);
} else {
throw new RuntimeException("unexpected action");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.dao.IncorrectUpdateSemanticsDataAccessException;
Expand Down Expand Up @@ -176,7 +177,8 @@ private Identifier getParentKeys(DbAction.WithDependingOn<?> action, JdbcConvert
Object id = getParentId(action);

JdbcIdentifierBuilder identifier = JdbcIdentifierBuilder //
.forBackReferences(converter, context.getAggregatePath(action.getPropertyPath()), id);
.forBackReferences(converter, context.getAggregatePath(action.getPropertyPath()),
getValueProvider(id, context.getAggregatePath(action.getPropertyPath()), converter));

for (Map.Entry<PersistentPropertyPath<RelationalPersistentProperty>, Object> qualifier : action.getQualifiers()
.entrySet()) {
Expand All @@ -186,6 +188,22 @@ private Identifier getParentKeys(DbAction.WithDependingOn<?> action, JdbcConvert
return identifier.build();
}

static Function<AggregatePath, Object> getValueProvider(Object idValue, AggregatePath path, JdbcConverter converter) {

RelationalPersistentEntity<?> entity = converter.getMappingContext()
.getPersistentEntity(path.getIdDefiningParentPath().getRequiredIdProperty().getType());

Function<AggregatePath, Object> valueProvider = ap -> {
if (entity == null) {
return idValue;
} else {
PersistentPropertyPathAccessor<Object> propertyPathAccessor = entity.getPropertyPathAccessor(idValue);
return propertyPathAccessor.getProperty(ap.getRequiredPersistentPropertyPath());
}
};
return valueProvider;
}

private Object getParentId(DbAction.WithDependingOn<?> action) {

DbAction.WithEntity<?> idOwningAction = getIdOwningAction(action,
Expand Down Expand Up @@ -267,12 +285,10 @@ <T> List<T> populateIdsIfNecessary() {

if (newEntity != action.getEntity()) {

cascadingValues.stage(insert.getDependingOn(), insert.getPropertyPath(),
qualifierValue, newEntity);
cascadingValues.stage(insert.getDependingOn(), insert.getPropertyPath(), qualifierValue, newEntity);
} else if (insert.getPropertyPath().getLeafProperty().isCollectionLike()) {

cascadingValues.gather(insert.getDependingOn(), insert.getPropertyPath(),
qualifierValue, newEntity);
cascadingValues.gather(insert.getDependingOn(), insert.getPropertyPath(), qualifierValue, newEntity);
}
}
}
Expand Down Expand Up @@ -359,8 +375,8 @@ private <T> void updateWithVersion(DbAction.UpdateRoot<T> update) {
*/
private static class StagedValues {

static final List<MultiValueAggregator<?>> aggregators = Arrays.asList(SetAggregator.INSTANCE, MapAggregator.INSTANCE,
ListAggregator.INSTANCE, SingleElementAggregator.INSTANCE);
static final List<MultiValueAggregator<?>> aggregators = Arrays.asList(SetAggregator.INSTANCE,
MapAggregator.INSTANCE, ListAggregator.INSTANCE, SingleElementAggregator.INSTANCE);

Map<DbAction, Map<PersistentPropertyPath, StagedValue>> values = new HashMap<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public <T> Object insert(T instance, Class<T> domainType, Identifier identifier,
public <T> Object[] insert(List<InsertSubject<T>> insertSubjects, Class<T> domainType, IdValueSource idValueSource) {

Assert.notEmpty(insertSubjects, "Batch insert must contain at least one InsertSubject");

SqlIdentifierParameterSource[] sqlParameterSources = insertSubjects.stream()
.map(insertSubject -> sqlParametersFactory.forInsert( //
insertSubject.getInstance(), //
Expand Down Expand Up @@ -167,7 +168,7 @@ public <S> boolean updateWithVersion(S instance, Class<S> domainType, Number pre
public void delete(Object id, Class<?> domainType) {

String deleteByIdSql = sql(domainType).getDeleteById();
SqlParameterSource parameter = sqlParametersFactory.forQueryById(id, domainType, ID_SQL_PARAMETER);
SqlParameterSource parameter = sqlParametersFactory.forQueryById(id, domainType);

operations.update(deleteByIdSql, parameter);
}
Expand All @@ -188,7 +189,7 @@ public <T> void deleteWithVersion(Object id, Class<T> domainType, Number previou

RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(domainType);

SqlIdentifierParameterSource parameterSource = sqlParametersFactory.forQueryById(id, domainType, ID_SQL_PARAMETER);
SqlIdentifierParameterSource parameterSource = sqlParametersFactory.forQueryById(id, domainType);
parameterSource.addValue(VERSION_SQL_PARAMETER, previousVersion);
int affectedRows = operations.update(sql(domainType).getDeleteByIdAndVersion(), parameterSource);

Expand All @@ -208,8 +209,7 @@ public void delete(Object rootId, PersistentPropertyPath<RelationalPersistentPro

String delete = sql(rootEntity.getType()).createDeleteByPath(propertyPath);

SqlIdentifierParameterSource parameters = sqlParametersFactory.forQueryById(rootId, rootEntity.getType(),
ROOT_ID_PARAMETER);
SqlIdentifierParameterSource parameters = sqlParametersFactory.forQueryById(rootId, rootEntity.getType());
operations.update(delete, parameters);
}

Expand Down Expand Up @@ -243,7 +243,7 @@ public void deleteAll(PersistentPropertyPath<RelationalPersistentProperty> prope
public <T> void acquireLockById(Object id, LockMode lockMode, Class<T> domainType) {

String acquireLockByIdSql = sql(domainType).getAcquireLockById(lockMode);
SqlIdentifierParameterSource parameter = sqlParametersFactory.forQueryById(id, domainType, ID_SQL_PARAMETER);
SqlIdentifierParameterSource parameter = sqlParametersFactory.forQueryById(id, domainType);

operations.query(acquireLockByIdSql, parameter, ResultSet::next);
}
Expand All @@ -269,7 +269,7 @@ public long count(Class<?> domainType) {
public <T> T findById(Object id, Class<T> domainType) {

String findOneSql = sql(domainType).getFindOne();
SqlIdentifierParameterSource parameter = sqlParametersFactory.forQueryById(id, domainType, ID_SQL_PARAMETER);
SqlIdentifierParameterSource parameter = sqlParametersFactory.forQueryById(id, domainType);

try {
return operations.queryForObject(findOneSql, parameter, getEntityRowMapper(domainType));
Expand Down Expand Up @@ -355,7 +355,7 @@ public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
public <T> boolean existsById(Object id, Class<T> domainType) {

String existsSql = sql(domainType).getExists();
SqlParameterSource parameter = sqlParametersFactory.forQueryById(id, domainType, ID_SQL_PARAMETER);
SqlParameterSource parameter = sqlParametersFactory.forQueryById(id, domainType);

Boolean result = operations.queryForObject(existsSql, parameter, Boolean.class);
Assert.state(result != null, "The result of an exists query must not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,25 @@ public static Identifier from(Map<SqlIdentifier, Object> map) {
return new Identifier(Collections.unmodifiableList(values));
}

/**
* Creates a new {@link Identifier} from the current instance and sets the value from {@link Identifier}. Existing key
* definitions for {@code name} are overwritten if they already exist.
*
* @param identifier the identifier to append.
* @return the {@link Identifier} containing all existing keys and the key part for {@code name}, {@code value}, and a
* {@link Class target type}.
* @since 4.0
*/
public Identifier withPart(Identifier identifier) {

Identifier result = this;
for (SingleIdentifierValue part : identifier.getParts()) {
result = result.withPart(part.getName(), part.getValue(), part.getTargetType());
}

return result;
}

/**
* Creates a new {@link Identifier} from the current instance and sets the value for {@code key}. Existing key
* definitions for {@code name} are overwritten if they already exist.
Expand Down

This file was deleted.

Loading