Browse Source

Omit Sequence value generation when identifier value is provided or the entity is not new.

Signed-off-by: mipo256 <mikhailpolivakha@gmail.com>

Closes #2003
Original pull request: #2005
pull/2034/head
mipo256 10 months ago committed by Mark Paluch
parent
commit
0fc3187916
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 1
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java
  2. 115
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/mapping/IdGeneratingBeforeSaveCallback.java
  3. 3
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/AbstractJdbcRepositoryLookUpStrategyTests.java
  4. 200
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java
  5. 52
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java
  6. 8
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-db2.sql
  7. 7
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-h2.sql
  8. 7
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-hsql.sql
  9. 6
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-mariadb.sql
  10. 11
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-mssql.sql
  11. 6
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-mysql.sql
  12. 21
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-oracle.sql
  13. 9
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-postgres.sql

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

@ -557,7 +557,6 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { @@ -557,7 +557,6 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
}
private <T> RootAggregateChange<T> createUpdateChange(EntityAndPreviousVersion<T> entityAndVersion) {
RootAggregateChange<T> aggregateChange = MutableAggregateChange.forSave(entityAndVersion.entity,
entityAndVersion.version);
new RelationalEntityUpdateWriter<T>(context).write(entityAndVersion.entity, aggregateChange);

115
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/mapping/IdGeneratingBeforeSaveCallback.java

@ -2,6 +2,7 @@ package org.springframework.data.jdbc.core.mapping; @@ -2,6 +2,7 @@ package org.springframework.data.jdbc.core.mapping;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;
@ -16,59 +17,73 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; @@ -16,59 +17,73 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.Assert;
/**
* Callback for generating ID via the database sequence. By default, it is registered as a
* bean in {@link AbstractJdbcConfiguration}
* Callback for generating ID via the database sequence. By default, it is registered as a bean in
* {@link AbstractJdbcConfiguration}
*
* @author Mikhail Polivakha
*/
public class IdGeneratingBeforeSaveCallback implements BeforeSaveCallback<Object> {
private static final Log LOG = LogFactory.getLog(IdGeneratingBeforeSaveCallback.class);
private final RelationalMappingContext relationalMappingContext;
private final Dialect dialect;
private final NamedParameterJdbcOperations operations;
public IdGeneratingBeforeSaveCallback(
RelationalMappingContext relationalMappingContext,
Dialect dialect,
NamedParameterJdbcOperations namedParameterJdbcOperations
) {
this.relationalMappingContext = relationalMappingContext;
this.dialect = dialect;
this.operations = namedParameterJdbcOperations;
}
@Override
public Object onBeforeSave(Object aggregate, MutableAggregateChange<Object> aggregateChange) {
Assert.notNull(aggregate, "The aggregate cannot be null at this point");
RelationalPersistentEntity<?> persistentEntity = relationalMappingContext.getPersistentEntity(aggregate.getClass());
Optional<SqlIdentifier> idSequence = persistentEntity.getIdSequence();
if (dialect.getIdGeneration().sequencesSupported()) {
if (persistentEntity.getIdProperty() != null) {
idSequence
.map(s -> dialect.getIdGeneration().createSequenceQuery(s))
.ifPresent(sql -> {
Long idValue = operations.queryForObject(sql, Map.of(), (rs, rowNum) -> rs.getLong(1));
PersistentPropertyAccessor<Object> propertyAccessor = persistentEntity.getPropertyAccessor(aggregate);
propertyAccessor.setProperty(persistentEntity.getRequiredIdProperty(), idValue);
});
}
} else {
if (idSequence.isPresent()) {
LOG.warn("""
It seems you're trying to insert an aggregate of type '%s' annotated with @TargetSequence, but the problem is RDBMS you're
working with does not support sequences as such. Falling back to identity columns
"""
.formatted(aggregate.getClass().getName())
);
}
}
return aggregate;
}
private static final Log LOG = LogFactory.getLog(IdGeneratingBeforeSaveCallback.class);
private final RelationalMappingContext relationalMappingContext;
private final Dialect dialect;
private final NamedParameterJdbcOperations operations;
public IdGeneratingBeforeSaveCallback(RelationalMappingContext relationalMappingContext, Dialect dialect,
NamedParameterJdbcOperations namedParameterJdbcOperations) {
this.relationalMappingContext = relationalMappingContext;
this.dialect = dialect;
this.operations = namedParameterJdbcOperations;
}
@Override
public Object onBeforeSave(Object aggregate, MutableAggregateChange<Object> aggregateChange) {
Assert.notNull(aggregate, "The aggregate cannot be null at this point");
RelationalPersistentEntity<?> persistentEntity = relationalMappingContext.getPersistentEntity(aggregate.getClass());
if (!persistentEntity.hasIdProperty()) {
return aggregate;
}
// we're doing INSERT and ID property value is not set explicitly by client
if (persistentEntity.isNew(aggregate) && !hasIdentifierValue(aggregate, persistentEntity)) {
return potentiallyFetchIdFromSequence(aggregate, persistentEntity);
} else {
return aggregate;
}
}
private boolean hasIdentifierValue(Object aggregate, RelationalPersistentEntity<?> persistentEntity) {
Object identifier = persistentEntity.getIdentifierAccessor(aggregate).getIdentifier();
if (persistentEntity.getIdProperty().getType().isPrimitive()) {
return identifier instanceof Number num && num.longValue() != 0L;
} else {
return identifier != null;
}
}
private Object potentiallyFetchIdFromSequence(Object aggregate, RelationalPersistentEntity<?> persistentEntity) {
Optional<SqlIdentifier> idSequence = persistentEntity.getIdSequence();
if (dialect.getIdGeneration().sequencesSupported()) {
idSequence.map(s -> dialect.getIdGeneration().createSequenceQuery(s)).ifPresent(sql -> {
Long idValue = operations.queryForObject(sql, Map.of(), (rs, rowNum) -> rs.getLong(1));
PersistentPropertyAccessor<Object> propertyAccessor = persistentEntity.getPropertyAccessor(aggregate);
propertyAccessor.setProperty(persistentEntity.getRequiredIdProperty(), idValue);
});
} else {
if (idSequence.isPresent()) {
LOG.warn("""
It seems you're trying to insert an aggregate of type '%s' annotated with @TargetSequence, but the problem is RDBMS you're
working with does not support sequences as such. Falling back to identity columns
""".formatted(aggregate.getClass().getName()));
}
}
return aggregate;
}
}

3
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/AbstractJdbcRepositoryLookUpStrategyTests.java

@ -28,6 +28,7 @@ import org.springframework.data.jdbc.testing.DatabaseType; @@ -28,6 +28,7 @@ import org.springframework.data.jdbc.testing.DatabaseType;
import org.springframework.data.jdbc.testing.EnabledOnDatabase;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
/**
@ -40,7 +41,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -40,7 +41,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
abstract class AbstractJdbcRepositoryLookUpStrategyTests {
@Autowired protected OnesRepository onesRepository;
@Autowired NamedParameterJdbcTemplate template;
@Autowired NamedParameterJdbcOperations template;
@Autowired RelationalMappingContext context;
void insertTestInstances() {

200
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIdGenerationIntegrationTests.java

@ -15,13 +15,14 @@ @@ -15,13 +15,14 @@
*/
package org.springframework.data.jdbc.repository;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@ -29,31 +30,53 @@ import org.springframework.context.annotation.Configuration; @@ -29,31 +30,53 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceCreator;
import org.springframework.data.annotation.Transient;
import org.springframework.data.domain.Persistable;
import org.springframework.data.jdbc.core.mapping.IdGeneratingBeforeSaveCallback;
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository;
import org.springframework.data.jdbc.testing.IntegrationTest;
import org.springframework.data.jdbc.testing.TestConfiguration;
import org.springframework.data.relational.core.conversion.MutableAggregateChange;
import org.springframework.data.relational.core.mapping.NamingStrategy;
import org.springframework.data.relational.core.mapping.Sequence;
import org.springframework.data.relational.core.mapping.event.BeforeConvertCallback;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.ListCrudRepository;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.test.context.jdbc.Sql;
/**
* Testing special cases for id generation with {@link SimpleJdbcRepository}.
*
* @author Jens Schauder
* @author Greg Turnquist
* @author Mikhail Polivakha
*/
@IntegrationTest
class JdbcRepositoryIdGenerationIntegrationTests {
@Autowired NamedParameterJdbcTemplate template;
@Autowired ReadOnlyIdEntityRepository readOnlyIdRepository;
@Autowired PrimitiveIdEntityRepository primitiveIdRepository;
@Autowired ImmutableWithManualIdEntityRepository immutableWithManualIdEntityRepository;
@Autowired
ReadOnlyIdEntityRepository readOnlyIdRepository;
@Autowired
PrimitiveIdEntityRepository primitiveIdRepository;
@Autowired
ImmutableWithManualIdEntityRepository immutableWithManualIdEntityRepository;
@Test // DATAJDBC-98
@Autowired
SimpleSeqRepository simpleSeqRepository;
@Autowired
PersistableSeqRepository persistableSeqRepository;
@Autowired
PrimitiveIdSeqRepository primitiveIdSeqRepository;
@Autowired
IdGeneratingBeforeSaveCallback idGeneratingCallback;
@Test
// DATAJDBC-98
void idWithoutSetterGetsSet() {
ReadOnlyIdEntity entity = readOnlyIdRepository.save(new ReadOnlyIdEntity(null, "Entity Name"));
@ -67,7 +90,8 @@ class JdbcRepositoryIdGenerationIntegrationTests { @@ -67,7 +90,8 @@ class JdbcRepositoryIdGenerationIntegrationTests {
});
}
@Test // DATAJDBC-98
@Test
// DATAJDBC-98
void primitiveIdGetsSet() {
PrimitiveIdEntity entity = new PrimitiveIdEntity();
@ -84,7 +108,8 @@ class JdbcRepositoryIdGenerationIntegrationTests { @@ -84,7 +108,8 @@ class JdbcRepositoryIdGenerationIntegrationTests {
});
}
@Test // DATAJDBC-393
@Test
// DATAJDBC-393
void manuallyGeneratedId() {
ImmutableWithManualIdEntity entity = new ImmutableWithManualIdEntity(null, "immutable");
@ -95,7 +120,8 @@ class JdbcRepositoryIdGenerationIntegrationTests { @@ -95,7 +120,8 @@ class JdbcRepositoryIdGenerationIntegrationTests {
assertThat(immutableWithManualIdEntityRepository.findAll()).hasSize(1);
}
@Test // DATAJDBC-393
@Test
// DATAJDBC-393
void manuallyGeneratedIdForSaveAll() {
ImmutableWithManualIdEntity one = new ImmutableWithManualIdEntity(null, "one");
@ -107,18 +133,146 @@ class JdbcRepositoryIdGenerationIntegrationTests { @@ -107,18 +133,146 @@ class JdbcRepositoryIdGenerationIntegrationTests {
assertThat(immutableWithManualIdEntityRepository.findAll()).hasSize(2);
}
private interface PrimitiveIdEntityRepository extends ListCrudRepository<PrimitiveIdEntity, Long> {}
@Test // DATAJDBC-2003
@Sql(statements = "INSERT INTO SimpleSeq(id, name) VALUES(1, 'initial value');")
void testUpdateAggregateWithSequence() {
SimpleSeq entity = new SimpleSeq();
entity.id = 1L;
entity.name = "New name";
AtomicReference<SimpleSeq> afterCallback = mockIdGeneratingCallback(entity);
SimpleSeq updated = simpleSeqRepository.save(entity);
assertThat(updated.id).isEqualTo(1L);
assertThat(afterCallback.get()).isSameAs(entity);
assertThat(afterCallback.get().id).isEqualTo(1L);
}
@Test
// DATAJDBC-2003
void testInsertPersistableAggregateWithSequenceClientIdIsFavored() {
long initialId = 1L;
PersistableSeq entityWithSeq = PersistableSeq.createNew(initialId, "name");
AtomicReference<PersistableSeq> afterCallback = mockIdGeneratingCallback(entityWithSeq);
PersistableSeq saved = persistableSeqRepository.save(entityWithSeq);
// We do not expect the SELECT next value from sequence in case we're doing an INSERT with ID provided by the client
assertThat(saved.getId()).isEqualTo(initialId);
assertThat(afterCallback.get()).isSameAs(entityWithSeq);
}
@Test
// DATAJDBC-2003
void testInsertAggregateWithSequenceAndUnsetPrimitiveId() {
private interface ReadOnlyIdEntityRepository extends ListCrudRepository<ReadOnlyIdEntity, Long> {}
PrimitiveIdSeq entity = new PrimitiveIdSeq();
entity.name = "some name";
AtomicReference<PrimitiveIdSeq> afterCallback = mockIdGeneratingCallback(entity);
private interface ImmutableWithManualIdEntityRepository extends ListCrudRepository<ImmutableWithManualIdEntity, Long> {}
PrimitiveIdSeq saved = primitiveIdSeqRepository.save(entity);
// 1. Select from sequence
// 2. Actual INSERT
assertThat(afterCallback.get().id).isEqualTo(1L);
assertThat(saved.id).isEqualTo(1L); // sequence starts with 1
}
@SuppressWarnings("unchecked")
private <T> AtomicReference<T> mockIdGeneratingCallback(T entity) {
AtomicReference<T> afterCallback = new AtomicReference<>();
Mockito
.doAnswer(invocationOnMock -> {
afterCallback.set((T) invocationOnMock.callRealMethod());
return afterCallback.get();
})
.when(idGeneratingCallback)
.onBeforeSave(Mockito.eq(entity), Mockito.any(MutableAggregateChange.class));
return afterCallback;
}
interface PrimitiveIdEntityRepository extends ListCrudRepository<PrimitiveIdEntity, Long> {
}
interface ReadOnlyIdEntityRepository extends ListCrudRepository<ReadOnlyIdEntity, Long> {
}
interface ImmutableWithManualIdEntityRepository extends ListCrudRepository<ImmutableWithManualIdEntity, Long> {
}
interface SimpleSeqRepository extends ListCrudRepository<SimpleSeq, Long> {
}
interface PersistableSeqRepository extends ListCrudRepository<PersistableSeq, Long> {
}
interface PrimitiveIdSeqRepository extends ListCrudRepository<PrimitiveIdSeq, Long> {
}
record ReadOnlyIdEntity(@Id Long id, String name) {
}
static class SimpleSeq {
@Id
@Sequence(value = "simple_seq_seq")
private Long id;
private String name;
}
static class PersistableSeq implements Persistable<Long> {
@Id
@Sequence(value = "persistable_seq_seq")
private Long id;
private String name;
@Transient
private boolean isNew;
@PersistenceCreator
public PersistableSeq() {
}
public PersistableSeq(Long id, String name, boolean isNew) {
this.id = id;
this.name = name;
this.isNew = isNew;
}
static PersistableSeq createNew(Long id, String name) {
return new PersistableSeq(id, name, true);
}
@Override
public Long getId() {
return id;
}
@Override
public boolean isNew() {
return isNew;
}
}
static class PrimitiveIdSeq {
@Id
@Sequence(value = "primitive_seq_seq")
private long id;
private String name;
}
static class PrimitiveIdEntity {
@Id private long id;
@Id
private long id;
String name;
public long getId() {
@ -142,17 +296,17 @@ class JdbcRepositoryIdGenerationIntegrationTests { @@ -142,17 +296,17 @@ class JdbcRepositoryIdGenerationIntegrationTests {
@Override
public Long id() {
return this.id;
}
return this.id;
}
public ImmutableWithManualIdEntity withId(Long id) {
return this.id == id ? this : new ImmutableWithManualIdEntity(id, this.name);
}
public ImmutableWithManualIdEntity withId(Long id) {
return this.id == id ? this : new ImmutableWithManualIdEntity(id, this.name);
}
public ImmutableWithManualIdEntity withName(String name) {
return this.name == name ? this : new ImmutableWithManualIdEntity(this.id, name);
}
public ImmutableWithManualIdEntity withName(String name) {
return this.name == name ? this : new ImmutableWithManualIdEntity(this.id, name);
}
}
@Configuration
@EnableJdbcRepositories(considerNestedRepositories = true,

52
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java

@ -23,6 +23,7 @@ import java.util.Optional; @@ -23,6 +23,7 @@ import java.util.Optional;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mockito.Mockito;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@ -68,6 +69,7 @@ import org.springframework.transaction.PlatformTransactionManager; @@ -68,6 +69,7 @@ import org.springframework.transaction.PlatformTransactionManager;
* @author Christoph Strobl
* @author Chirag Tailor
* @author Christopher Klein
* @author Mikhail Polivakha
*/
@Configuration
@ComponentScan // To pick up configuration classes (per activated profile)
@ -76,24 +78,25 @@ public class TestConfiguration { @@ -76,24 +78,25 @@ public class TestConfiguration {
public static final String PROFILE_SINGLE_QUERY_LOADING = "singleQueryLoading";
public static final String PROFILE_NO_SINGLE_QUERY_LOADING = "!" + PROFILE_SINGLE_QUERY_LOADING;
@Autowired DataSource dataSource;
@Autowired BeanFactory beanFactory;
@Autowired ApplicationEventPublisher publisher;
@Autowired(required = false) SqlSessionFactory sqlSessionFactory;
@Autowired
DataSource dataSource;
@Autowired
BeanFactory beanFactory;
@Autowired
ApplicationEventPublisher publisher;
@Autowired(required = false)
SqlSessionFactory sqlSessionFactory;
@Bean
JdbcRepositoryFactory jdbcRepositoryFactory(
@Qualifier("defaultDataAccessStrategy") DataAccessStrategy dataAccessStrategy, RelationalMappingContext context,
Dialect dialect, JdbcConverter converter, Optional<List<NamedQueries>> namedQueries,
List<EntityCallback<?>> callbacks,
List<EvaluationContextExtension> evaulationContextExtensions) {
List<EntityCallback<?>> callbacks, List<EvaluationContextExtension> evaulationContextExtensions) {
JdbcRepositoryFactory factory = new JdbcRepositoryFactory(dataAccessStrategy, context, converter, dialect,
publisher, namedParameterJdbcTemplate());
factory.setEntityCallbacks(
EntityCallbacks.create(callbacks.toArray(new EntityCallback[0]))
);
factory.setEntityCallbacks(EntityCallbacks.create(callbacks.toArray(new EntityCallback[0])));
namedQueries.map(it -> it.iterator().next()).ifPresent(factory::setNamedQueries);
@ -118,22 +121,24 @@ public class TestConfiguration { @@ -118,22 +121,24 @@ public class TestConfiguration {
@Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template, RelationalMappingContext context,
JdbcConverter converter, Dialect dialect) {
return new DataAccessStrategyFactory(new SqlGeneratorSource(context, converter, dialect), converter,
template, new SqlParametersFactory(context, converter),
new InsertStrategyFactory(template, dialect)).create();
return new DataAccessStrategyFactory(new SqlGeneratorSource(context, converter, dialect), converter, template,
new SqlParametersFactory(context, converter), new InsertStrategyFactory(template, dialect)).create();
}
@Bean("jdbcMappingContext")
@Profile(PROFILE_NO_SINGLE_QUERY_LOADING)
JdbcMappingContext jdbcMappingContextWithOutSingleQueryLoading(Optional<NamingStrategy> namingStrategy, CustomConversions conversions) {
JdbcMappingContext jdbcMappingContextWithOutSingleQueryLoading(Optional<NamingStrategy> namingStrategy,
CustomConversions conversions) {
JdbcMappingContext mappingContext = new JdbcMappingContext(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE));
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
return mappingContext;
}
@Bean("jdbcMappingContext")
@Profile(PROFILE_SINGLE_QUERY_LOADING)
JdbcMappingContext jdbcMappingContextWithSingleQueryLoading(Optional<NamingStrategy> namingStrategy, CustomConversions conversions) {
JdbcMappingContext jdbcMappingContextWithSingleQueryLoading(Optional<NamingStrategy> namingStrategy,
CustomConversions conversions) {
JdbcMappingContext mappingContext = new JdbcMappingContext(namingStrategy.orElse(DefaultNamingStrategy.INSTANCE));
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
@ -144,8 +149,9 @@ public class TestConfiguration { @@ -144,8 +149,9 @@ public class TestConfiguration {
@Bean
CustomConversions jdbcCustomConversions(Dialect dialect) {
SimpleTypeHolder simpleTypeHolder = dialect.simpleTypes().isEmpty() ? JdbcSimpleTypes.HOLDER
: new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER);
SimpleTypeHolder simpleTypeHolder = dialect.simpleTypes().isEmpty() ?
JdbcSimpleTypes.HOLDER :
new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER);
return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)),
Collections.emptyList());
@ -164,8 +170,9 @@ public class TestConfiguration { @@ -164,8 +170,9 @@ public class TestConfiguration {
CustomConversions conversions, @Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template,
Dialect dialect) {
JdbcArrayColumns arrayColumns = dialect instanceof JdbcDialect ? ((JdbcDialect) dialect).getArraySupport()
: JdbcArrayColumns.DefaultSupport.INSTANCE;
JdbcArrayColumns arrayColumns = dialect instanceof JdbcDialect ?
((JdbcDialect) dialect).getArraySupport() :
JdbcArrayColumns.DefaultSupport.INSTANCE;
return new MappingJdbcConverter( //
mappingContext, //
@ -181,12 +188,9 @@ public class TestConfiguration { @@ -181,12 +188,9 @@ public class TestConfiguration {
* @return must not be {@literal null}.
*/
@Bean
public IdGeneratingBeforeSaveCallback idGeneratingBeforeSaveCallback(
JdbcMappingContext mappingContext,
NamedParameterJdbcOperations operations,
Dialect dialect
) {
return new IdGeneratingBeforeSaveCallback(mappingContext, dialect, operations);
public IdGeneratingBeforeSaveCallback idGeneratingBeforeSaveCallback(JdbcMappingContext mappingContext,
NamedParameterJdbcOperations operations, Dialect dialect) {
return Mockito.spy(new IdGeneratingBeforeSaveCallback(mappingContext, dialect, operations));
}
@Bean

8
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-db2.sql

@ -1,7 +1,15 @@ @@ -1,7 +1,15 @@
DROP TABLE ReadOnlyIdEntity;
DROP TABLE PrimitiveIdEntity;
DROP TABLE ImmutableWithManualIdentity;
DROP TABLE EntityWithSeq;
DROP TABLE PrimitiveIdEntityWithSeq;
CREATE TABLE ReadOnlyIdEntity (ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE PrimitiveIdEntity (ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE ImmutableWithManualIdentity (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE SimpleSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE simple_seq_seq START WITH 1;
CREATE TABLE PersistableSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE persistable_seq_seq START WITH 1;
CREATE TABLE PrimitiveIdSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE primitive_seq_seq START WITH 1;

7
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-h2.sql

@ -3,3 +3,10 @@ @@ -3,3 +3,10 @@
CREATE TABLE ReadOnlyIdEntity (ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE PrimitiveIdEntity (ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE ImmutableWithManualIdentity (ID BIGINT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE SimpleSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE simple_seq_seq START WITH 1;
CREATE TABLE PersistableSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE persistable_seq_seq START WITH 1;
CREATE TABLE PrimitiveIdSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE primitive_seq_seq START WITH 1;

7
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-hsql.sql

@ -3,3 +3,10 @@ @@ -3,3 +3,10 @@
CREATE TABLE ReadOnlyIdEntity (ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE PrimitiveIdEntity (ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE ImmutableWithManualIdentity (ID BIGINT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE SimpleSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE "simple_seq_seq" START WITH 1;
CREATE TABLE PersistableSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE "persistable_seq_seq" START WITH 1;
CREATE TABLE PrimitiveIdSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE "primitive_seq_seq" START WITH 1;

6
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-mariadb.sql

@ -1,3 +1,9 @@ @@ -1,3 +1,9 @@
CREATE TABLE ReadOnlyIdEntity (ID BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE PrimitiveIdEntity (ID BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE ImmutableWithManualIdentity (ID BIGINT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE SimpleSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE simple_seq_seq START WITH 1;
CREATE TABLE PersistableSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE persistable_seq_seq START WITH 1;
CREATE TABLE PrimitiveIdSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE primitive_seq_seq START WITH 1;

11
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-mssql.sql

@ -1,8 +1,17 @@ @@ -1,8 +1,17 @@
DROP TABLE IF EXISTS ReadOnlyIdEntity;
DROP TABLE IF EXISTS PrimitiveIdEntity;
DROP TABLE IF EXISTS ImmutableWithManualIdentity;
DROP TABLE IF EXISTS EntityWithSeq;
DROP TABLE IF EXISTS PersistableEntityWithSeq;
DROP TABLE IF EXISTS PrimitiveIdEntityWithSeq;
CREATE TABLE ReadOnlyIdEntity (ID BIGINT IDENTITY PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE PrimitiveIdEntity (ID BIGINT IDENTITY PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE ImmutableWithManualIdentity (ID BIGINT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE EntityWithSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE SimpleSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE simple_seq_seq START WITH 1;
CREATE TABLE PersistableSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE persistable_seq_seq START WITH 1;
CREATE TABLE PrimitiveIdSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE primitive_seq_seq START WITH 1;

6
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-mysql.sql

@ -1,3 +1,9 @@ @@ -1,3 +1,9 @@
CREATE TABLE ReadOnlyIdEntity (ID BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE PrimitiveIdEntity (ID BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE ImmutableWithManualIdentity (ID BIGINT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE SimpleSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE simple_seq_seq START WITH 1;
CREATE TABLE PersistableSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE persistable_seq_seq START WITH 1;
CREATE TABLE PrimitiveIdSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE primitive_seq_seq START WITH 1;

21
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-oracle.sql

@ -16,3 +16,24 @@ CREATE TABLE ImmutableWithManualIdentity ( @@ -16,3 +16,24 @@ CREATE TABLE ImmutableWithManualIdentity (
ID NUMBER PRIMARY KEY,
NAME VARCHAR2(100)
);
CREATE TABLE SimpleSeq (
ID NUMBER PRIMARY KEY,
NAME VARCHAR2(100)
);
CREATE SEQUENCE simple_seq_seq START WITH 1;
CREATE TABLE PersistableSeq (
ID NUMBER PRIMARY KEY,
NAME VARCHAR2(100)
);
CREATE SEQUENCE persistable_seq_seq START WITH 1;
CREATE TABLE PrimitiveIdSeq (
ID NUMBER PRIMARY KEY,
NAME VARCHAR2(100)
);
CREATE SEQUENCE primitive_seq_seq START WITH 1;

9
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIdGenerationIntegrationTests-postgres.sql

@ -1,7 +1,16 @@ @@ -1,7 +1,16 @@
DROP TABLE ReadOnlyIdEntity;
DROP TABLE PrimitiveIdEntity;
DROP TABLE ImmutableWithManualIdentity;
DROP TABLE EntityWithSeq;
DROP TABLE PersistableEntityWithSeq;
DROP TABLE PrimitiveIdEntityWithSeq;
CREATE TABLE ReadOnlyIdEntity (ID SERIAL PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE PrimitiveIdEntity (ID SERIAL PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE ImmutableWithManualIdentity (ID BIGINT PRIMARY KEY, NAME VARCHAR(100));
CREATE TABLE SimpleSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE simple_seq_seq START WITH 1;
CREATE TABLE PersistableSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE persistable_seq_seq START WITH 1;
CREATE TABLE PrimitiveIdSeq (ID BIGINT NOT NULL PRIMARY KEY, NAME VARCHAR(100));
CREATE SEQUENCE primitive_seq_seq START WITH 1;
Loading…
Cancel
Save