#444 - Initialize primitive Id properties upon INSERT.
We now propagate auto-generated Id values to primitive Id properties if the value in the domain model is zero. This happens in addition to non-primitive values being null to ensure that generated values end up in the domain model.
This commit is contained in:
@@ -604,13 +604,22 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R
|
||||
PersistentPropertyAccessor<?> propertyAccessor = entity.getPropertyAccessor(object);
|
||||
RelationalPersistentProperty idProperty = entity.getRequiredIdProperty();
|
||||
|
||||
if (propertyAccessor.getProperty(idProperty) != null) {
|
||||
return object;
|
||||
boolean idPropertyUpdateNeeded = false;
|
||||
|
||||
Object id = propertyAccessor.getProperty(idProperty);
|
||||
if (idProperty.getType().isPrimitive()) {
|
||||
idPropertyUpdateNeeded = id instanceof Number && ((Number) id).longValue() == 0;
|
||||
} else {
|
||||
idPropertyUpdateNeeded = id == null;
|
||||
}
|
||||
|
||||
return potentiallySetId(row, metadata, propertyAccessor, idProperty) //
|
||||
if (idPropertyUpdateNeeded) {
|
||||
return potentiallySetId(row, metadata, propertyAccessor, idProperty) //
|
||||
? (T) propertyAccessor.getBean() //
|
||||
: object;
|
||||
}
|
||||
|
||||
return object;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
@@ -105,26 +106,27 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
|
||||
*/
|
||||
protected abstract String getCreateTableStatement();
|
||||
|
||||
@Test
|
||||
@Test // gh-444
|
||||
public void shouldSaveNewObject() {
|
||||
|
||||
LegoSet legoSet = new LegoSet(null, "SCHAUFELRADBAGGER", 12);
|
||||
|
||||
repository.save(legoSet) //
|
||||
repository.save(new LegoSet(0, "SCHAUFELRADBAGGER", 12)) //
|
||||
.as(StepVerifier::create) //
|
||||
.consumeNextWith(actual -> {
|
||||
|
||||
assertThat(actual.getId()).isNotNull();
|
||||
}).verifyComplete();
|
||||
|
||||
Map<String, Object> map = jdbc.queryForMap("SELECT * FROM legoset");
|
||||
assertThat(map).containsEntry("name", "SCHAUFELRADBAGGER").containsEntry("manual", 12).containsKey("id");
|
||||
repository.save(new LegoSet(0, "SCHAUFELRADBAGGER", 12)) //
|
||||
.as(StepVerifier::create) //
|
||||
.consumeNextWith(actual -> {
|
||||
|
||||
assertThat(actual.getId()).isGreaterThan(0);
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // gh-93
|
||||
public void shouldSaveNewObjectAndSetVersionIfWrapperVersionPropertyExists() {
|
||||
|
||||
LegoSetVersionable legoSet = new LegoSetVersionable(null, "SCHAUFELRADBAGGER", 12, null);
|
||||
LegoSetVersionable legoSet = new LegoSetVersionable(0, "SCHAUFELRADBAGGER", 12, null);
|
||||
|
||||
repository.save(legoSet) //
|
||||
.as(StepVerifier::create) //
|
||||
@@ -142,7 +144,7 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
|
||||
@Test // gh-93
|
||||
public void shouldSaveNewObjectAndSetVersionIfPrimitiveVersionPropertyExists() {
|
||||
|
||||
LegoSetPrimitiveVersionable legoSet = new LegoSetPrimitiveVersionable(null, "SCHAUFELRADBAGGER", 12, 0);
|
||||
LegoSetPrimitiveVersionable legoSet = new LegoSetPrimitiveVersionable(0, "SCHAUFELRADBAGGER", 12, 0);
|
||||
|
||||
repository.save(legoSet) //
|
||||
.as(StepVerifier::create) //
|
||||
@@ -216,10 +218,10 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
|
||||
@Test
|
||||
public void shouldSaveObjectsUsingIterable() {
|
||||
|
||||
LegoSet legoSet1 = new LegoSet(null, "SCHAUFELRADBAGGER", 12);
|
||||
LegoSet legoSet2 = new LegoSet(null, "FORSCHUNGSSCHIFF", 13);
|
||||
LegoSet legoSet3 = new LegoSet(null, "RALLYEAUTO", 14);
|
||||
LegoSet legoSet4 = new LegoSet(null, "VOLTRON", 15);
|
||||
LegoSet legoSet1 = new LegoSet(0, "SCHAUFELRADBAGGER", 12);
|
||||
LegoSet legoSet2 = new LegoSet(0, "FORSCHUNGSSCHIFF", 13);
|
||||
LegoSet legoSet3 = new LegoSet(0, "RALLYEAUTO", 14);
|
||||
LegoSet legoSet4 = new LegoSet(0, "VOLTRON", 15);
|
||||
|
||||
repository.saveAll(Arrays.asList(legoSet1, legoSet2, legoSet3, legoSet4)) //
|
||||
.map(LegoSet::getManual) //
|
||||
@@ -237,8 +239,8 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
|
||||
@Test
|
||||
public void shouldSaveObjectsUsingPublisher() {
|
||||
|
||||
LegoSet legoSet1 = new LegoSet(null, "SCHAUFELRADBAGGER", 12);
|
||||
LegoSet legoSet2 = new LegoSet(null, "FORSCHUNGSSCHIFF", 13);
|
||||
LegoSet legoSet1 = new LegoSet(0, "SCHAUFELRADBAGGER", 12);
|
||||
LegoSet legoSet2 = new LegoSet(0, "FORSCHUNGSSCHIFF", 13);
|
||||
|
||||
repository.saveAll(Flux.just(legoSet1, legoSet2)) //
|
||||
.as(StepVerifier::create) //
|
||||
@@ -468,27 +470,11 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
|
||||
@Table("legoset")
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
static class LegoSet implements Persistable<Integer> {
|
||||
@Id Integer id;
|
||||
static class LegoSet {
|
||||
@Id int id;
|
||||
String name;
|
||||
Integer manual;
|
||||
|
||||
@Override
|
||||
public boolean isNew() {
|
||||
return id == null;
|
||||
}
|
||||
}
|
||||
|
||||
static class AlwaysNewLegoSet extends LegoSet {
|
||||
|
||||
AlwaysNewLegoSet(Integer id, String name, Integer manual) {
|
||||
super(id, name, manual);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNew() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@@ -497,7 +483,7 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
|
||||
static class LegoSetVersionable extends LegoSet {
|
||||
@Version Integer version;
|
||||
|
||||
public LegoSetVersionable(Integer id, String name, Integer manual, Integer version) {
|
||||
public LegoSetVersionable(int id, String name, Integer manual, Integer version) {
|
||||
super(id, name, manual);
|
||||
this.version = version;
|
||||
}
|
||||
@@ -509,7 +495,7 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
|
||||
static class LegoSetPrimitiveVersionable extends LegoSet {
|
||||
@Version int version;
|
||||
|
||||
public LegoSetPrimitiveVersionable(Integer id, String name, Integer manual, int version) {
|
||||
public LegoSetPrimitiveVersionable(int id, String name, Integer manual, int version) {
|
||||
super(id, name, manual);
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.data.r2dbc.repository.support;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -27,11 +29,19 @@ import javax.sql.DataSource;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.TransientDataAccessException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
|
||||
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
|
||||
import org.springframework.data.r2dbc.testing.H2TestSupport;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.repository.query.RelationalEntityInformation;
|
||||
import org.springframework.data.relational.repository.support.MappingRelationalEntityInformation;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@@ -44,6 +54,10 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
@ContextConfiguration
|
||||
public class H2SimpleR2dbcRepositoryIntegrationTests extends AbstractSimpleR2dbcRepositoryIntegrationTests {
|
||||
|
||||
@Autowired private R2dbcEntityTemplate entityTemplate;
|
||||
|
||||
@Autowired private RelationalMappingContext mappingContext;
|
||||
|
||||
@Configuration
|
||||
static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration {
|
||||
|
||||
@@ -67,21 +81,30 @@ public class H2SimpleR2dbcRepositoryIntegrationTests extends AbstractSimpleR2dbc
|
||||
public void shouldInsertNewObjectWithGivenId() {
|
||||
|
||||
try {
|
||||
this.jdbc.execute("DROP TABLE legoset");
|
||||
this.jdbc.execute("DROP TABLE always_new");
|
||||
} catch (DataAccessException e) {}
|
||||
|
||||
this.jdbc.execute(H2TestSupport.CREATE_TABLE_LEGOSET);
|
||||
this.jdbc.execute("CREATE TABLE always_new (\n" //
|
||||
+ " id integer PRIMARY KEY,\n" //
|
||||
+ " name varchar(255) NOT NULL" //
|
||||
+ ");");
|
||||
|
||||
AlwaysNewLegoSet legoSet = new AlwaysNewLegoSet(9999, "SCHAUFELRADBAGGER", 12);
|
||||
RelationalEntityInformation<AlwaysNew, Long> entityInformation = new MappingRelationalEntityInformation<>(
|
||||
(RelationalPersistentEntity<AlwaysNew>) mappingContext.getRequiredPersistentEntity(AlwaysNew.class));
|
||||
|
||||
repository.save(legoSet) //
|
||||
SimpleR2dbcRepository<AlwaysNew, Long> repository = new SimpleR2dbcRepository<>(entityInformation, entityTemplate,
|
||||
entityTemplate.getConverter());
|
||||
|
||||
AlwaysNew alwaysNew = new AlwaysNew(9999L, "SCHAUFELRADBAGGER");
|
||||
|
||||
repository.save(alwaysNew) //
|
||||
.as(StepVerifier::create) //
|
||||
.consumeNextWith( //
|
||||
actual -> assertThat(actual.getId()).isEqualTo(9999) //
|
||||
).verifyComplete();
|
||||
|
||||
Map<String, Object> map = jdbc.queryForMap("SELECT * FROM legoset");
|
||||
assertThat(map).containsEntry("name", "SCHAUFELRADBAGGER").containsEntry("manual", 12).containsKey("id");
|
||||
Map<String, Object> map = jdbc.queryForMap("SELECT * FROM always_new");
|
||||
assertThat(map).containsEntry("name", "SCHAUFELRADBAGGER").containsKey("id");
|
||||
}
|
||||
|
||||
@Test // gh-232
|
||||
@@ -97,4 +120,17 @@ public class H2SimpleR2dbcRepositoryIntegrationTests extends AbstractSimpleR2dbc
|
||||
.hasMessage("Failed to update table [legoset]. Row with Id [9999] does not exist.");
|
||||
});
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
static class AlwaysNew implements Persistable<Long> {
|
||||
|
||||
@Id Long id;
|
||||
String name;
|
||||
|
||||
@Override
|
||||
public boolean isNew() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user