Use Converter-based projection for R2DBC repository queries.
Previously, we instantiated the underlying entity. Now, we either read results directly into the result type or use a Map-backed projection. Closes #1687
This commit is contained in:
@@ -159,6 +159,22 @@ public interface R2dbcEntityOperations extends FluentR2dbcOperations {
|
||||
*/
|
||||
<T> RowsFetchSpec<T> query(PreparedOperation<?> operation, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a {@link RowsFetchSpec}, given {@link PreparedOperation}. Any provided bindings within
|
||||
* {@link PreparedOperation} are applied to the underlying {@link DatabaseClient}. The query is issued as-is without
|
||||
* additional pre-processing such as named parameter expansion. Results of the query are mapped onto
|
||||
* {@code entityClass}.
|
||||
*
|
||||
* @param operation the prepared operation wrapping a SQL query and bind parameters.
|
||||
* @param entityClass the entity type must not be {@literal null}.
|
||||
* @param resultType the returned entity, type must not be {@literal null}.
|
||||
* @return a {@link RowsFetchSpec} ready to materialize.
|
||||
* @throws DataAccessException if there is any problem issuing the execution.
|
||||
* @since 3.2.1
|
||||
*/
|
||||
<T> RowsFetchSpec<T> query(PreparedOperation<?> operation, Class<?> entityClass, Class<T> resultType)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a {@link RowsFetchSpec}, given {@link PreparedOperation}. Any provided bindings within
|
||||
* {@link PreparedOperation} are applied to the underlying {@link DatabaseClient}. The query is issued as-is without
|
||||
@@ -234,6 +250,9 @@ public interface R2dbcEntityOperations extends FluentR2dbcOperations {
|
||||
<T> RowsFetchSpec<T> query(PreparedOperation<?> operation, Class<?> entityClass,
|
||||
BiFunction<Row, RowMetadata, T> rowMapper) throws DataAccessException;
|
||||
|
||||
<T> RowsFetchSpec<T> getRowsFetchSpec(DatabaseClient.GenericExecuteSpec executeSpec, Class<?> entityType,
|
||||
Class<T> resultType);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with entities
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -419,11 +419,16 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
|
||||
|
||||
@Override
|
||||
public <T> RowsFetchSpec<T> query(PreparedOperation<?> operation, Class<T> entityClass) {
|
||||
return query(operation, entityClass, entityClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> RowsFetchSpec<T> query(PreparedOperation<?> operation, Class<?> entityClass, Class<T> resultType) throws DataAccessException {
|
||||
|
||||
Assert.notNull(operation, "PreparedOperation must not be null");
|
||||
Assert.notNull(entityClass, "Entity class must not be null");
|
||||
|
||||
return new EntityCallbackAdapter<>(getRowsFetchSpec(databaseClient.sql(operation), entityClass, entityClass),
|
||||
return new EntityCallbackAdapter<>(getRowsFetchSpec(databaseClient.sql(operation), entityClass, resultType),
|
||||
getTableNameOrEmpty(entityClass));
|
||||
}
|
||||
|
||||
@@ -774,7 +779,7 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw
|
||||
return query.getColumns().stream().map(table::column).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private <T> RowsFetchSpec<T> getRowsFetchSpec(DatabaseClient.GenericExecuteSpec executeSpec, Class<?> entityType,
|
||||
public <T> RowsFetchSpec<T> getRowsFetchSpec(DatabaseClient.GenericExecuteSpec executeSpec, Class<?> entityType,
|
||||
Class<T> resultType) {
|
||||
|
||||
boolean simpleType = getConverter().isSimpleType(resultType);
|
||||
|
||||
@@ -90,13 +90,15 @@ public abstract class AbstractR2dbcQuery implements RepositoryQuery {
|
||||
} else if (isExistsQuery()) {
|
||||
fetchSpec = entityOperations.getDatabaseClient().sql(operation).map(row -> true);
|
||||
} else {
|
||||
fetchSpec = entityOperations.query(operation, resolveResultType(processor));
|
||||
fetchSpec = entityOperations.query(operation, processor.getReturnedType()
|
||||
.getDomainType(),
|
||||
resolveResultType(processor));
|
||||
}
|
||||
|
||||
R2dbcQueryExecution execution = new ResultProcessingExecution(getExecutionToWrap(processor.getReturnedType()),
|
||||
new ResultProcessingConverter(processor, converter.getMappingContext(), instantiators));
|
||||
|
||||
return execution.execute(RowsFetchSpec.class.cast(fetchSpec));
|
||||
return execution.execute((RowsFetchSpec) fetchSpec);
|
||||
}
|
||||
|
||||
Class<?> resolveResultType(ResultProcessor resultProcessor) {
|
||||
@@ -107,7 +109,7 @@ public abstract class AbstractR2dbcQuery implements RepositoryQuery {
|
||||
return returnedType.getDomainType();
|
||||
}
|
||||
|
||||
return returnedType.isProjecting() ? returnedType.getDomainType() : returnedType.getReturnedType();
|
||||
return returnedType.getReturnedType();
|
||||
}
|
||||
|
||||
private R2dbcQueryExecution getExecutionToWrap(ReturnedType returnedType) {
|
||||
@@ -122,17 +124,17 @@ public abstract class AbstractR2dbcQuery implements RepositoryQuery {
|
||||
|
||||
if (Boolean.class.isAssignableFrom(returnedType.getReturnedType())) {
|
||||
return fs.rowsUpdated().map(integer -> integer > 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (Number.class.isAssignableFrom(returnedType.getReturnedType())) {
|
||||
if (Number.class.isAssignableFrom(returnedType.getReturnedType())) {
|
||||
|
||||
return fs.rowsUpdated()
|
||||
.map(count -> converter.getConversionService().convert(count, returnedType.getReturnedType()));
|
||||
}
|
||||
}
|
||||
|
||||
if (ReflectionUtils.isVoid(returnedType.getReturnedType())) {
|
||||
if (ReflectionUtils.isVoid(returnedType.getReturnedType())) {
|
||||
return fs.rowsUpdated().then();
|
||||
}
|
||||
}
|
||||
|
||||
return fs.rowsUpdated();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user