#69 - Allow object creation with a subset of columns.

We now allow object creation when not all columns are present by leveraging R2DBC RowMetadata. A column subset is necessary for projections.
This commit is contained in:
Mark Paluch
2019-05-22 09:41:23 +02:00
parent 972bc09606
commit 46082147d3
9 changed files with 70 additions and 17 deletions

View File

@@ -43,6 +43,6 @@ public class EntityRowMapper<T> implements BiFunction<Row, RowMetadata, T> {
*/
@Override
public T apply(Row row, RowMetadata metadata) {
return converter.read(typeRoRead, row);
return converter.read(typeRoRead, row, metadata);
}
}

View File

@@ -84,8 +84,21 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R
// Entity reading
// ----------------------------------
/*
* (non-Javadoc)
* @see org.springframework.data.convert.EntityReader#read(java.lang.Class, S)
*/
@Override
public <R> R read(Class<R> type, Row row) {
return read(type, row, null);
}
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.convert.R2dbcConverter#read(java.lang.Class, io.r2dbc.spi.Row, io.r2dbc.spi.RowMetadata)
*/
@Override
public <R> R read(Class<R> type, Row row, @Nullable RowMetadata metadata) {
TypeInformation<? extends R> typeInfo = ClassTypeInformation.from(type);
Class<? extends R> rawType = typeInfo.getType();
@@ -99,10 +112,10 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R
return getConversionService().convert(row, rawType);
}
return read(getRequiredPersistentEntity(type), row);
return read(getRequiredPersistentEntity(type), row, metadata);
}
private <R> R read(RelationalPersistentEntity<R> entity, Row row) {
private <R> R read(RelationalPersistentEntity<R> entity, Row row, @Nullable RowMetadata metadata) {
R result = createInstance(row, "", entity);
@@ -115,7 +128,7 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R
continue;
}
Object value = readFrom(row, property, "");
Object value = readFrom(row, metadata, property, "");
if (value != null) {
propertyAccessor.setProperty(property, value);
@@ -129,20 +142,27 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R
* Read a single value or a complete Entity from the {@link Row} passed as an argument.
*
* @param row the {@link Row} to extract the value from. Must not be {@literal null}.
* @param metadata the {@link RowMetadata}. Can be {@literal null}.
* @param property the {@link RelationalPersistentProperty} for which the value is intended. Must not be
* {@literal null}.
* @param prefix to be used for all column names accessed by this method. Must not be {@literal null}.
* @return the value read from the {@link Row}. May be {@literal null}.
*/
private Object readFrom(Row row, RelationalPersistentProperty property, String prefix) {
private Object readFrom(Row row, @Nullable RowMetadata metadata, RelationalPersistentProperty property,
String prefix) {
try {
if (property.isEntity()) {
return readEntityFrom(row, property);
return readEntityFrom(row, metadata, property);
}
Object value = row.get(prefix + property.getColumnName());
String identifier = prefix + property.getColumnName();
if (metadata != null && !metadata.getColumnNames().contains(identifier)) {
return null;
}
Object value = row.get(identifier);
return getPotentiallyConvertedSimpleRead(value, property.getTypeInformation().getType());
} catch (Exception o_O) {
@@ -178,13 +198,13 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R
}
@SuppressWarnings("unchecked")
private <S> S readEntityFrom(Row row, PersistentProperty<?> property) {
private <S> S readEntityFrom(Row row, RowMetadata metadata, PersistentProperty<?> property) {
String prefix = property.getName() + "_";
RelationalPersistentEntity<?> entity = getMappingContext().getRequiredPersistentEntity(property.getActualType());
if (readFrom(row, entity.getRequiredIdProperty(), prefix) == null) {
if (readFrom(row, metadata, entity.getRequiredIdProperty(), prefix) == null) {
return null;
}
@@ -195,7 +215,7 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R
for (RelationalPersistentProperty p : entity) {
if (!entity.isConstructorArgument(property)) {
propertyAccessor.setProperty(p, readFrom(row, p, prefix));
propertyAccessor.setProperty(p, readFrom(row, metadata, p, prefix));
}
}
@@ -213,6 +233,10 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R
// Entity writing
// ----------------------------------
/*
* (non-Javadoc)
* @see org.springframework.data.convert.EntityWriter#write(java.lang.Object, java.lang.Object)
*/
@Override
public void write(Object source, OutboundRow sink) {
@@ -313,6 +337,11 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R
return Enum.class.isAssignableFrom(value.getClass()) ? ((Enum<?>) value).name() : value;
}
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.convert.R2dbcConverter#getArrayValue(org.springframework.data.r2dbc.dialect.ArrayColumns, org.springframework.data.relational.core.mapping.RelationalPersistentProperty, java.lang.Object)
*/
@Override
public Object getArrayValue(ArrayColumns arrayColumns, RelationalPersistentProperty property, Object value) {
Class<?> targetType = arrayColumns.getArrayType(property.getActualType());
@@ -337,6 +366,7 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R
* @param object must not be {@literal null}.
* @return
*/
@Override
@SuppressWarnings("unchecked")
public <T> BiFunction<Row, RowMetadata, T> populateIdIfNecessary(T object) {

View File

@@ -71,4 +71,14 @@ public interface R2dbcConverter
* @return
*/
<T> BiFunction<Row, RowMetadata, T> populateIdIfNecessary(T object);
/**
* Reads the given source into the given type.
*
* @param type they type to convert the given source to.
* @param source the source to create an object of the given type from.
* @param metadata the {@link RowMetadata}.
* @return
*/
<R> R read(Class<R> type, Row source, RowMetadata metadata);
}