DATAJDBC-96 - Database based ID generation.

No longer using batch inserts, which won't (easily) hold up for long anyway, since we need to decide between update and insert anyway. If one wants to support batch insert one also has to check if any autoid columns are present, because those seem not to work with batch inserts with many or at least some drivers.

Related ticket: SPR-1836.
Original pull request: #5.
This commit is contained in:
Jens Schauder
2017-02-27 08:22:19 +01:00
committed by Oliver Gierke
parent 2181d8d3c6
commit 21490b8397
4 changed files with 54 additions and 14 deletions

View File

@@ -50,4 +50,8 @@ public class JdbcPersistentEntity<T> extends BasicPersistentEntity<T, JdbcPersis
public Object getIdValue(T instance) {
return getPropertyAccessor(instance).getProperty(getIdProperty());
}
public void setId(T instance, Object value) {
getPropertyAccessor(instance).setProperty(getIdProperty(),value);
}
}

View File

@@ -28,6 +28,8 @@ import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
/**
* @author Jens Schauder
@@ -50,22 +52,24 @@ public class SimpleJdbcRepository<T, ID extends Serializable> implements CrudRep
}
@Override
public <S extends T> S save(S entity) {
public <S extends T> S save(S instance) {
template.update(sql.getInsert(), getPropertyMap(entity));
KeyHolder holder = new GeneratedKeyHolder();
return entity;
template.update(
sql.getInsert(),
new MapSqlParameterSource(getPropertyMap(instance)),
holder);
entity.setId(instance, holder.getKey());
return instance;
}
@Override
public <S extends T> Iterable<S> save(Iterable<S> entities) {
Map<String, ?>[] batchValues = StreamSupport
.stream(entities.spliterator(), false)
.map(i -> getPropertyMap(i))
.toArray(size -> new Map[size]);
template.batchUpdate(sql.getInsert(), batchValues);
entities.forEach(this::save);
return entities;
}

View File

@@ -19,9 +19,7 @@ import static java.util.Arrays.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
import java.sql.SQLException;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
@@ -91,6 +89,26 @@ public class JdbcRepositoryIntegrationTests {
reloadedEntity.getName());
}
@Test
public void canSaveAndLoadAnEntityWithDatabaseBasedIdGeneration() {
entity = createDummyEntity(null);
entity = repository.save(entity);
assertThat(entity).isNotNull();
DummyEntity reloadedEntity = repository.findOne(entity.getId());
assertEquals(
entity.getId(),
reloadedEntity.getId());
assertEquals(
entity.getName(),
reloadedEntity.getName());
}
@Test
public void saveMany() {
@@ -101,6 +119,21 @@ public class JdbcRepositoryIntegrationTests {
assertThat(repository.findAll()).extracting(DummyEntity::getId).containsExactlyInAnyOrder(23L, 24L);
}
@Test
public void saveManyWithIdGeneration() {
DummyEntity one = createDummyEntity(null);
DummyEntity two = createDummyEntity(null);
Iterable<DummyEntity> entities = repository.save(asList(one, two));
assertThat(entities).allMatch(e -> e.getId() != null);
assertThat(repository.findAll())
.extracting(DummyEntity::getId)
.containsExactlyInAnyOrder(new Long[]{one.getId(), two.getId()});
}
@Test
public void existsReturnsTrueIffEntityExists() {
@@ -195,13 +228,12 @@ public class JdbcRepositoryIntegrationTests {
}
private static DummyEntityRepository createRepository(EmbeddedDatabase db) {
return new JdbcRepositoryFactory(db).getRepository(DummyEntityRepository.class);
}
private static DummyEntity createDummyEntity(long id) {
private static DummyEntity createDummyEntity(Long id) {
DummyEntity entity = new DummyEntity();
entity.setId(id);

View File

@@ -1 +1 @@
CREATE TABLE dummyentity (ID BIGINT, NAME VARCHAR(100), PRIMARY KEY (ID))
CREATE TABLE dummyentity (ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 4711) PRIMARY KEY, NAME VARCHAR(100))