Skip to content

Commit d6d9957

Browse files
mp911deschauder
authored andcommitted
Introduce MappingRelationalConverter.
Add sophisticated converter to read aggregates from a RowDocument including support for maps, collections, subdocuments, and embeddables considering registered converters. Use ResultSetRowDocumentExtractor to extract result multi-sets into RowDocument and then later apply object mapping. Original pull request #1604 Closes #1586
1 parent 48b037f commit d6d9957

23 files changed

+2490
-1434
lines changed

Diff for: spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/AggregateReader.java

+41-25
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.springframework.data.jdbc.core.convert;
1717

18+
import java.sql.ResultSet;
19+
import java.sql.SQLException;
1820
import java.util.ArrayList;
1921
import java.util.Iterator;
2022
import java.util.List;
@@ -27,73 +29,87 @@
2729
import org.springframework.data.relational.core.sqlgeneration.AliasFactory;
2830
import org.springframework.data.relational.core.sqlgeneration.SingleQuerySqlGenerator;
2931
import org.springframework.data.relational.core.sqlgeneration.SqlGenerator;
32+
import org.springframework.data.relational.domain.RowDocument;
3033
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
3134
import org.springframework.lang.Nullable;
3235
import org.springframework.util.Assert;
3336

3437
/**
3538
* Reads complete Aggregates from the database, by generating appropriate SQL using a {@link SingleQuerySqlGenerator}
36-
* and a matching {@link AggregateResultSetExtractor} and invoking a
37-
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
39+
* through {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}. Results are converterd into an
40+
* intermediate {@link ResultSetRowDocumentExtractor RowDocument} and mapped via
41+
* {@link org.springframework.data.relational.core.conversion.RelationalConverter#read(Class, RowDocument)}.
3842
*
3943
* @param <T> the type of aggregate produced by this reader.
4044
* @author Jens Schauder
45+
* @author Mark Paluch
4146
* @since 3.2
4247
*/
4348
class AggregateReader<T> {
4449

45-
private final RelationalPersistentEntity<T> aggregate;
50+
private final RelationalPersistentEntity<T> entity;
4651
private final org.springframework.data.relational.core.sqlgeneration.SqlGenerator sqlGenerator;
4752
private final JdbcConverter converter;
4853
private final NamedParameterJdbcOperations jdbcTemplate;
49-
private final AggregateResultSetExtractor<T> extractor;
54+
private final ResultSetRowDocumentExtractor extractor;
5055

5156
AggregateReader(Dialect dialect, JdbcConverter converter, AliasFactory aliasFactory,
52-
NamedParameterJdbcOperations jdbcTemplate, RelationalPersistentEntity<T> aggregate) {
57+
NamedParameterJdbcOperations jdbcTemplate, RelationalPersistentEntity<T> entity) {
5358

5459
this.converter = converter;
55-
this.aggregate = aggregate;
60+
this.entity = entity;
5661
this.jdbcTemplate = jdbcTemplate;
5762

5863
this.sqlGenerator = new CachingSqlGenerator(
59-
new SingleQuerySqlGenerator(converter.getMappingContext(), aliasFactory, dialect, aggregate));
64+
new SingleQuerySqlGenerator(converter.getMappingContext(), aliasFactory, dialect, entity));
6065

61-
this.extractor = new AggregateResultSetExtractor<>(aggregate, converter, createPathToColumnMapping(aliasFactory));
66+
this.extractor = new ResultSetRowDocumentExtractor(converter.getMappingContext(),
67+
createPathToColumnMapping(aliasFactory));
6268
}
6369

6470
public List<T> findAll() {
65-
66-
Iterable<T> result = jdbcTemplate.query(sqlGenerator.findAll(), extractor);
67-
68-
Assert.state(result != null, "result is null");
69-
70-
return (List<T>) result;
71+
return jdbcTemplate.query(sqlGenerator.findAll(), this::extractAll);
7172
}
7273

7374
@Nullable
7475
public T findById(Object id) {
7576

76-
id = converter.writeValue(id, aggregate.getRequiredIdProperty().getTypeInformation());
77+
id = converter.writeValue(id, entity.getRequiredIdProperty().getTypeInformation());
7778

78-
Iterator<T> result = jdbcTemplate.query(sqlGenerator.findById(), Map.of("id", id), extractor).iterator();
79+
return jdbcTemplate.query(sqlGenerator.findById(), Map.of("id", id), rs -> {
7980

80-
T returnValue = result.hasNext() ? result.next() : null;
81+
Iterator<RowDocument> iterate = extractor.iterate(entity, rs);
82+
if (iterate.hasNext()) {
8183

82-
if (result.hasNext()) {
83-
throw new IncorrectResultSizeDataAccessException(1);
84-
}
85-
86-
return returnValue;
84+
RowDocument object = iterate.next();
85+
if (iterate.hasNext()) {
86+
throw new IncorrectResultSizeDataAccessException(1);
87+
}
88+
return converter.read(entity.getType(), object);
89+
}
90+
return null;
91+
});
8792
}
8893

8994
public Iterable<T> findAllById(Iterable<?> ids) {
9095

9196
List<Object> convertedIds = new ArrayList<>();
9297
for (Object id : ids) {
93-
convertedIds.add(converter.writeValue(id, aggregate.getRequiredIdProperty().getTypeInformation()));
98+
convertedIds.add(converter.writeValue(id, entity.getRequiredIdProperty().getTypeInformation()));
9499
}
95100

96-
return jdbcTemplate.query(sqlGenerator.findAllById(), Map.of("ids", convertedIds), extractor);
101+
return jdbcTemplate.query(sqlGenerator.findAllById(), Map.of("ids", convertedIds), this::extractAll);
102+
}
103+
104+
private List<T> extractAll(ResultSet rs) throws SQLException {
105+
106+
Iterator<RowDocument> iterate = extractor.iterate(entity, rs);
107+
List<T> resultList = new ArrayList<>();
108+
while (iterate.hasNext()) {
109+
resultList.add(converter.read(entity.getType(), iterate.next()));
110+
}
111+
112+
return resultList;
97113
}
98114

99115
private PathToColumnMapping createPathToColumnMapping(AliasFactory aliasFactory) {
@@ -117,8 +133,8 @@ public String keyColumn(AggregatePath path) {
117133
* A wrapper for the {@link org.springframework.data.relational.core.sqlgeneration.SqlGenerator} that caches the
118134
* generated statements.
119135
*
120-
* @since 3.2
121136
* @author Jens Schauder
137+
* @since 3.2
122138
*/
123139
static class CachingSqlGenerator implements org.springframework.data.relational.core.sqlgeneration.SqlGenerator {
124140

0 commit comments

Comments
 (0)