Browse Source

#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.
pull/1188/head
Mark Paluch 5 years ago
parent
commit
7d3bd1f30a
No known key found for this signature in database
GPG Key ID: 51A00FA751B91849
  1. 15
      src/main/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverter.java
  2. 56
      src/test/java/org/springframework/data/r2dbc/repository/support/AbstractSimpleR2dbcRepositoryIntegrationTests.java
  3. 48
      src/test/java/org/springframework/data/r2dbc/repository/support/H2SimpleR2dbcRepositoryIntegrationTests.java

15
src/main/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverter.java

@ -604,13 +604,22 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R @@ -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;
};
}

56
src/test/java/org/springframework/data/r2dbc/repository/support/AbstractSimpleR2dbcRepositoryIntegrationTests.java

@ -33,6 +33,7 @@ import javax.sql.DataSource; @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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;
}

48
src/test/java/org/springframework/data/r2dbc/repository/support/H2SimpleR2dbcRepositoryIntegrationTests.java

@ -18,6 +18,8 @@ package org.springframework.data.r2dbc.repository.support; @@ -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; @@ -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; @@ -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 @@ -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 @@ -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;
}
}
}

Loading…
Cancel
Save