DATAJDBC-266 - Entities referenced by 1:1 don't need an Id.
The id-property was used to determine if there is an instance at all, or if it was null. For entities that don't have an id that purpose is now fulfilled by selecting the backreference and checking it against null. See also: DATAJDBC-223.
This commit is contained in:
committed by
Greg Turnquist
parent
f46a01dbd8
commit
0816f4182e
@@ -21,7 +21,6 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
@@ -118,21 +117,17 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
@Nullable
|
||||
private Object readFrom(ResultSet resultSet, RelationalPersistentProperty property, String prefix) {
|
||||
|
||||
try {
|
||||
|
||||
if (property.isEntity()) {
|
||||
return readEntityFrom(resultSet, property);
|
||||
}
|
||||
|
||||
return converter.readValue(resultSet.getObject(prefix + property.getColumnName()), property.getTypeInformation());
|
||||
|
||||
} catch (SQLException o_O) {
|
||||
throw new MappingException(String.format("Could not read property %s from result set!", property), o_O);
|
||||
if (property.isEntity()) {
|
||||
return readEntityFrom(resultSet, property);
|
||||
}
|
||||
|
||||
Object value = getObjectFromResultSet(resultSet, prefix + property.getColumnName());
|
||||
return converter.readValue(value, property.getTypeInformation());
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <S> S readEntityFrom(ResultSet rs, PersistentProperty<?> property) {
|
||||
private <S> S readEntityFrom(ResultSet rs, RelationalPersistentProperty property) {
|
||||
|
||||
String prefix = property.getName() + "_";
|
||||
|
||||
@@ -140,7 +135,12 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
RelationalPersistentEntity<S> entity = (RelationalPersistentEntity<S>) context
|
||||
.getRequiredPersistentEntity(property.getActualType());
|
||||
|
||||
if (readFrom(rs, entity.getRequiredIdProperty(), prefix) == null) {
|
||||
RelationalPersistentProperty idProperty = entity.getIdProperty();
|
||||
|
||||
if ((idProperty != null //
|
||||
? readFrom(rs, idProperty, prefix) //
|
||||
: getObjectFromResultSet(rs, prefix + property.getReverseColumnName()) //
|
||||
) == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -155,6 +155,16 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object getObjectFromResultSet(ResultSet rs, String backreferenceName) {
|
||||
|
||||
try {
|
||||
return rs.getObject(backreferenceName);
|
||||
} catch (SQLException o_O) {
|
||||
throw new MappingException(String.format("Could not read value %s from result set!", backreferenceName), o_O);
|
||||
}
|
||||
}
|
||||
|
||||
private <S> S createInstance(RelationalPersistentEntity<S> entity, ResultSet rs, String prefix) {
|
||||
|
||||
return converter.createInstance(entity, parameter -> {
|
||||
|
||||
@@ -201,6 +201,17 @@ class SqlGenerator {
|
||||
.as(joinAlias + "_" + refProperty.getColumnName()) //
|
||||
);
|
||||
}
|
||||
|
||||
// if the referenced property doesn't have an id, include the back reference in the select list.
|
||||
// this enables determining if the referenced entity is present or null.
|
||||
if (!refEntity.hasIdProperty()) {
|
||||
|
||||
builder.column( //
|
||||
cb -> cb.tableAlias(joinAlias) //
|
||||
.column(property.getReverseColumnName()) //
|
||||
.as(joinAlias + "_" + property.getReverseColumnName()) //
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -210,6 +210,52 @@ public class AggregateTemplateIntegrationTests {
|
||||
assertThat(reloadedLegoSet.manual.content).isEqualTo("new content");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-266
|
||||
public void oneToOneChildWithoutId() {
|
||||
|
||||
OneToOneParent parent = new OneToOneParent();
|
||||
|
||||
parent.content = "parent content";
|
||||
parent.child = new OneToOneChildNoId();
|
||||
parent.child.content = "child content";
|
||||
|
||||
template.save(parent);
|
||||
|
||||
OneToOneParent reloaded = template.findById(parent.id, OneToOneParent.class);
|
||||
|
||||
assertThat(reloaded.child.content).isEqualTo("child content");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-266
|
||||
public void oneToOneNullChildWithoutId() {
|
||||
|
||||
OneToOneParent parent = new OneToOneParent();
|
||||
|
||||
parent.content = "parent content";
|
||||
parent.child = null;
|
||||
|
||||
template.save(parent);
|
||||
|
||||
OneToOneParent reloaded = template.findById(parent.id, OneToOneParent.class);
|
||||
|
||||
assertThat(reloaded.child).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-266
|
||||
public void oneToOneNullAttributes() {
|
||||
|
||||
OneToOneParent parent = new OneToOneParent();
|
||||
|
||||
parent.content = "parent content";
|
||||
parent.child = new OneToOneChildNoId();
|
||||
|
||||
template.save(parent);
|
||||
|
||||
OneToOneParent reloaded = template.findById(parent.id, OneToOneParent.class);
|
||||
|
||||
assertThat(reloaded.child).isNotNull();
|
||||
}
|
||||
|
||||
private static LegoSet createLegoSet() {
|
||||
|
||||
LegoSet entity = new LegoSet();
|
||||
@@ -241,6 +287,18 @@ public class AggregateTemplateIntegrationTests {
|
||||
|
||||
}
|
||||
|
||||
static class OneToOneParent {
|
||||
|
||||
@Id private Long id;
|
||||
private String content;
|
||||
|
||||
private OneToOneChildNoId child;
|
||||
}
|
||||
|
||||
static class OneToOneChildNoId {
|
||||
private String content;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
static class Config {
|
||||
|
||||
@@ -186,6 +186,19 @@ public class SqlGeneratorUnitTests {
|
||||
assertThat(insert).endsWith("()");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-266
|
||||
public void joinForOneToOneWithoutIdIncludesTheBackReferenceOfTheOuterJoin() {
|
||||
|
||||
SqlGenerator sqlGenerator = createSqlGenerator(ParentOfNoIdChild.class);
|
||||
|
||||
String findAll = sqlGenerator.getFindAll();
|
||||
|
||||
assertThat(findAll).containsSequence(
|
||||
"SELECT",
|
||||
"child.parent_of_no_id_child AS child_parent_of_no_id_child",
|
||||
"FROM");
|
||||
}
|
||||
|
||||
private PersistentPropertyPath<RelationalPersistentProperty> getPath(String path, Class<?> base) {
|
||||
return PersistentPropertyPathTestUtils.getPath(context, path, base);
|
||||
}
|
||||
@@ -220,6 +233,15 @@ public class SqlGeneratorUnitTests {
|
||||
String content;
|
||||
}
|
||||
|
||||
static class ParentOfNoIdChild {
|
||||
@Id Long id;
|
||||
NoIdChild child;
|
||||
}
|
||||
|
||||
static class NoIdChild {
|
||||
|
||||
}
|
||||
|
||||
private static class PrefixingNamingStrategy implements NamingStrategy {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,3 +3,6 @@ CREATE TABLE MANUAL ( id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) P
|
||||
|
||||
ALTER TABLE MANUAL ADD FOREIGN KEY (LEGO_SET)
|
||||
REFERENCES LEGO_SET(id);
|
||||
|
||||
CREATE TABLE ONE_TO_ONE_PARENT ( id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, content VARCHAR(30));
|
||||
CREATE TABLE One_To_One_Child_No_Id (ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, content VARCHAR(30));
|
||||
|
||||
@@ -3,3 +3,6 @@ CREATE TABLE MANUAL ( id BIGINT AUTO_INCREMENT PRIMARY KEY, LEGO_SET BIGINT, CON
|
||||
|
||||
ALTER TABLE MANUAL ADD FOREIGN KEY (LEGO_SET)
|
||||
REFERENCES LEGO_SET(id);
|
||||
|
||||
CREATE TABLE ONE_TO_ONE_PARENT ( id BIGINT AUTO_INCREMENT PRIMARY KEY, content VARCHAR(30));
|
||||
CREATE TABLE One_To_One_Child_No_Id (ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, content VARCHAR(30));
|
||||
|
||||
@@ -3,3 +3,6 @@ CREATE TABLE MANUAL ( id BIGINT AUTO_INCREMENT PRIMARY KEY, LEGO_SET BIGINT, CON
|
||||
|
||||
ALTER TABLE MANUAL ADD FOREIGN KEY (LEGO_SET)
|
||||
REFERENCES LEGO_SET(id);
|
||||
|
||||
CREATE TABLE ONE_TO_ONE_PARENT ( id BIGINT AUTO_INCREMENT PRIMARY KEY, content VARCHAR(30));
|
||||
CREATE TABLE One_To_One_Child_No_Id (ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, content VARCHAR(30));
|
||||
|
||||
@@ -6,3 +6,6 @@ CREATE TABLE MANUAL ( id SERIAL PRIMARY KEY, LEGO_SET BIGINT, CONTENT VARCHAR(20
|
||||
|
||||
ALTER TABLE MANUAL ADD FOREIGN KEY (LEGO_SET)
|
||||
REFERENCES LEGO_SET(id);
|
||||
|
||||
CREATE TABLE ONE_TO_ONE_PARENT ( id SERIAL PRIMARY KEY, content VARCHAR(30));
|
||||
CREATE TABLE One_To_One_Child_No_Id (ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, content VARCHAR(30));
|
||||
|
||||
Reference in New Issue
Block a user