Browse Source

DATAJDBC-341 - Map NULL values in EntityRowMapper for columns not being fetched in the query.

Original pull request: #170.
pull/201/head
Thomas Lang 6 years ago committed by Jens Schauder
parent
commit
c2062dbb9d
No known key found for this signature in database
GPG Key ID: 996B1389BA0721C3
  1. 35
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java
  2. 55
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java

35
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java

@ -59,10 +59,10 @@ import org.springframework.util.Assert;
* @author Jens Schauder * @author Jens Schauder
* @author Christoph Strobl * @author Christoph Strobl
* @author Myeonghyeon Lee * @author Myeonghyeon Lee
* @since 1.1
* @see MappingContext * @see MappingContext
* @see SimpleTypeHolder * @see SimpleTypeHolder
* @see CustomConversions * @see CustomConversions
* @since 1.1
*/ */
public class BasicJdbcConverter extends BasicRelationalConverter implements JdbcConverter { public class BasicJdbcConverter extends BasicRelationalConverter implements JdbcConverter {
@ -401,7 +401,35 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
continue; continue;
} }
propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property)); // check if property is in the result set
// if not - leave it out
// DATAJDBC-341
if (property.isEntity() || property.isEmbedded()) {
propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property));
} else {
try {
if (resultSet.findColumn(property.getColumnName().getReference(identifierProcessing)) > 0) {
propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property));
} else {
try {
propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property));
} catch (Exception exception) {
LOG.info(
"The result set is not corresponding to the target entity. Left out properties will be set to standard values (NULL for reference types, 0 for primitives.");
}
}
} catch (SQLException e) {
String columnAlias = path.extendBy(property).getColumnAlias().getReference(identifierProcessing);
try {
if (resultSet.findColumn(columnAlias) > 0) {
propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property));
}
} catch (SQLException ex) {
LOG.info(String.format("Cannot find column named %s within the result set!", property.getColumnName()));
}
}
}
} }
return propertyAccessor.getBean(); return propertyAccessor.getBean();
@ -523,7 +551,8 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
try { try {
return resultSet.getObject(backreferenceName); return resultSet.getObject(backreferenceName);
} catch (SQLException o_O) { } catch (SQLException o_O) {
throw new MappingException(String.format("Could not read value %s from result set!", backreferenceName), o_O); LOG.info(String.format("Could not read value %s from result set! Use null as value.", backreferenceName), o_O);
return null;
} }
} }

55
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java

@ -32,11 +32,7 @@ import lombok.With;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -87,6 +83,35 @@ public class EntityRowMapperUnitTests {
} }
}; };
@Test // DATAJDBC-341
public void mapNotNeededValueTypePropertiesToNull() throws SQLException {
ResultSet rs = mockResultSet(singletonList("id"), //
ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha");
rs.next();
Trivial extracted = createRowMapper(Trivial.class).mapRow(rs, 1);
assertThat(extracted) //
.isNotNull() //
.extracting(e -> e.id, e -> e.name) //
.containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, null);
}
@Test // DATAJDBC-341
public void mapNotNeededPrimitiveTypePropertiesToNull() throws SQLException {
ResultSet rs = mockResultSet(singletonList("id"), //
ID_FOR_ENTITY_NOT_REFERENCING_MAP, "alpha");
rs.next();
TrivialMapPropertiesToNullIfNotNeeded extracted = createRowMapper(TrivialMapPropertiesToNullIfNotNeeded.class)
.mapRow(rs, 1);
assertThat(extracted) //
.isNotNull() //
.extracting(e -> e.id, e -> e.age) //
.containsExactly(ID_FOR_ENTITY_NOT_REFERENCING_MAP, 0);
}
@Test // DATAJDBC-113 @Test // DATAJDBC-113
public void simpleEntitiesGetProperlyExtracted() throws SQLException { public void simpleEntitiesGetProperlyExtracted() throws SQLException {
@ -477,6 +502,19 @@ public class EntityRowMapperUnitTests {
String name; String name;
} }
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
@Getter
static class TrivialMapPropertiesToNullIfNotNeeded {
@Id Long id;
int age;
String phone;
Boolean isSupreme;
long referenceToCustomer;
}
@EqualsAndHashCode @EqualsAndHashCode
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@ -762,11 +800,18 @@ public class EntityRowMapperUnitTests {
return isAfterLast() || isBeforeFirst() ? 0 : index + 1; return isAfterLast() || isBeforeFirst() ? 0 : index + 1;
case "toString": case "toString":
return this.toString(); return this.toString();
case "findColumn":
return isThereAColumnNamed(invocation.getArgument(0));
default: default:
throw new OperationNotSupportedException(invocation.getMethod().getName()); throw new OperationNotSupportedException(invocation.getMethod().getName());
} }
} }
private int isThereAColumnNamed(String name) {
Optional<Map<String, Object>> first = values.stream().filter(s -> s.equals(name)).findFirst();
return (first.isPresent()) ? 1 : 0;
}
private boolean isAfterLast() { private boolean isAfterLast() {
return index >= values.size() && !values.isEmpty(); return index >= values.size() && !values.isEmpty();
} }

Loading…
Cancel
Save