Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
<version>1.1.0.DATAJDBC-266-SNAPSHOT</version>

<name>Spring Data JDBC</name>
<description>Spring Data module for JDBC repositories.</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

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;
Expand Down Expand Up @@ -118,29 +117,30 @@ private T populateProperties(T result, ResultSet resultSet) {
@Nullable
private Object readFrom(ResultSet resultSet, RelationalPersistentProperty property, String prefix) {

try {

if (property.isEntity()) {
return readEntityFrom(resultSet, property);
}
if (property.isEntity()) {
return readEntityFrom(resultSet, property);
}

return converter.readValue(resultSet.getObject(prefix + property.getColumnName()), property.getTypeInformation());
Object value = getObjectFromResultSet(resultSet, prefix + property.getColumnName());
return converter.readValue(value, property.getTypeInformation());

} catch (SQLException o_O) {
throw new MappingException(String.format("Could not read property %s from result set!", property), o_O);
}
}

@Nullable
private <S> S readEntityFrom(ResultSet rs, PersistentProperty<?> property) {
private <S> S readEntityFrom(ResultSet rs, RelationalPersistentProperty property) {

String prefix = property.getName() + "_";

@SuppressWarnings("unchecked")
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;
}

Expand All @@ -155,6 +155,16 @@ private <S> S readEntityFrom(ResultSet rs, PersistentProperty<?> property) {
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 -> {
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/org/springframework/data/jdbc/core/SqlGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,17 @@ private void addColumnsAndJoinsForOneToOneReferences(SelectBuilder builder) {
.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()) //
);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,52 @@ public void changeReferencedEntity() {
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();
Expand Down Expand Up @@ -241,6 +287,18 @@ static class Manual {

}

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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,19 @@ public void getInsertForEmptyColumnList() {
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);
}
Expand Down Expand Up @@ -220,6 +233,15 @@ static class Element {
String content;
}

static class ParentOfNoIdChild {
@Id Long id;
NoIdChild child;
}

static class NoIdChild {

}

private static class PrefixingNamingStrategy implements NamingStrategy {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Original file line number Diff line number Diff line change
Expand Up @@ -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));