Skip to content

Commit 73d6788

Browse files
committed
Polishing.
Fix merge problems. Execute tests only for HsqlDb. Refactoring to use lists instead of streams. We try to avoid the latter, since they are prone to cause performance issues. Minor refactorings. See #771 See #230 Original pull request #1486
1 parent 1515a3a commit 73d6788

8 files changed

+299
-273
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 the original author or authors.
2+
* Copyright 2020-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,10 +22,11 @@
2222
import org.springframework.data.domain.Sort;
2323
import org.springframework.data.jdbc.core.convert.JdbcConverter;
2424
import org.springframework.data.jdbc.core.convert.QueryMapper;
25+
import org.springframework.data.mapping.Parameter;
2526
import org.springframework.data.mapping.PersistentPropertyPath;
2627
import org.springframework.data.relational.core.dialect.Dialect;
2728
import org.springframework.data.relational.core.dialect.RenderContextFactory;
28-
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
29+
import org.springframework.data.relational.core.mapping.AggregatePath;
2930
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
3031
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
3132
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
@@ -48,102 +49,110 @@
4849
import org.springframework.util.Assert;
4950

5051
/**
51-
* Implementation of {@link RelationalQueryCreator} that creates {@link Stream} of deletion {@link ParametrizedQuery}
52+
* Implementation of {@link RelationalQueryCreator} that creates {@link List} of deletion {@link ParametrizedQuery}
5253
* from a {@link PartTree}.
5354
*
5455
* @author Yunyoung LEE
55-
* @since 2.3
56+
* @author Nikita Konev
57+
* @since 3.5
5658
*/
57-
class JdbcDeleteQueryCreator extends RelationalQueryCreator<Stream<ParametrizedQuery>> {
59+
class JdbcDeleteQueryCreator extends RelationalQueryCreator<List<ParametrizedQuery>> {
5860

59-
private final RelationalMappingContext context;
60-
private final QueryMapper queryMapper;
61-
private final RelationalEntityMetadata<?> entityMetadata;
62-
private final RenderContextFactory renderContextFactory;
61+
private final RelationalMappingContext context;
62+
private final QueryMapper queryMapper;
63+
private final RelationalEntityMetadata<?> entityMetadata;
64+
private final RenderContextFactory renderContextFactory;
6365

64-
/**
65-
* Creates new instance of this class with the given {@link PartTree}, {@link JdbcConverter}, {@link Dialect},
66-
* {@link RelationalEntityMetadata} and {@link RelationalParameterAccessor}.
67-
*
68-
* @param context
69-
* @param tree part tree, must not be {@literal null}.
70-
* @param converter must not be {@literal null}.
71-
* @param dialect must not be {@literal null}.
72-
* @param entityMetadata relational entity metadata, must not be {@literal null}.
73-
* @param accessor parameter metadata provider, must not be {@literal null}.
74-
*/
75-
JdbcDeleteQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect,
76-
RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor) {
77-
super(tree, accessor);
66+
/**
67+
* Creates new instance of this class with the given {@link PartTree}, {@link JdbcConverter}, {@link Dialect},
68+
* {@link RelationalEntityMetadata} and {@link RelationalParameterAccessor}.
69+
*
70+
* @param context
71+
* @param tree part tree, must not be {@literal null}.
72+
* @param converter must not be {@literal null}.
73+
* @param dialect must not be {@literal null}.
74+
* @param entityMetadata relational entity metadata, must not be {@literal null}.
75+
* @param accessor parameter metadata provider, must not be {@literal null}.
76+
*/
77+
JdbcDeleteQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect,
78+
RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor) {
7879

79-
Assert.notNull(converter, "JdbcConverter must not be null");
80-
Assert.notNull(dialect, "Dialect must not be null");
81-
Assert.notNull(entityMetadata, "Relational entity metadata must not be null");
80+
super(tree, accessor);
8281

83-
this.context = context;
82+
Assert.notNull(converter, "JdbcConverter must not be null");
83+
Assert.notNull(dialect, "Dialect must not be null");
84+
Assert.notNull(entityMetadata, "Relational entity metadata must not be null");
8485

85-
this.entityMetadata = entityMetadata;
86-
this.queryMapper = new QueryMapper(dialect, converter);
87-
this.renderContextFactory = new RenderContextFactory(dialect);
88-
}
86+
this.context = context;
87+
this.entityMetadata = entityMetadata;
88+
this.queryMapper = new QueryMapper(converter);
89+
this.renderContextFactory = new RenderContextFactory(dialect);
90+
}
8991

90-
@Override
91-
protected Stream<ParametrizedQuery> complete(@Nullable Criteria criteria, Sort sort) {
92+
@Override
93+
protected List<ParametrizedQuery> complete(@Nullable Criteria criteria, Sort sort) {
9294

93-
RelationalPersistentEntity<?> entity = entityMetadata.getTableEntity();
94-
Table table = Table.create(entityMetadata.getTableName());
95-
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
95+
RelationalPersistentEntity<?> entity = entityMetadata.getTableEntity();
96+
Table table = Table.create(entityMetadata.getTableName());
97+
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
9698

97-
SqlContext sqlContext = new SqlContext(entity);
99+
SqlContext sqlContext = new SqlContext(entity);
98100

99-
Condition condition = criteria == null ? null
100-
: queryMapper.getMappedObject(parameterSource, criteria, table, entity);
101+
Condition condition = criteria == null ? null
102+
: queryMapper.getMappedObject(parameterSource, criteria, table, entity);
101103

102-
// create select criteria query for subselect
103-
SelectWhere selectBuilder = StatementBuilder.select(sqlContext.getIdColumn()).from(table);
104-
Select select = condition == null ? selectBuilder.build() : selectBuilder.where(condition).build();
104+
// create select criteria query for subselect
105+
SelectWhere selectBuilder = StatementBuilder.select(sqlContext.getIdColumn()).from(table);
106+
Select select = condition == null ? selectBuilder.build() : selectBuilder.where(condition).build();
105107

106-
// create delete relation queries
107-
List<Delete> deleteChain = new ArrayList<>();
108-
deleteRelations(deleteChain, entity, select);
108+
// create delete relation queries
109+
List<Delete> deleteChain = new ArrayList<>();
110+
deleteRelations(deleteChain, entity, select);
109111

110-
// crate delete query
111-
DeleteWhere deleteBuilder = StatementBuilder.delete(table);
112-
Delete delete = condition == null ? deleteBuilder.build() : deleteBuilder.where(condition).build();
112+
// crate delete query
113+
DeleteWhere deleteBuilder = StatementBuilder.delete(table);
114+
Delete delete = condition == null ? deleteBuilder.build() : deleteBuilder.where(condition).build();
113115

114-
deleteChain.add(delete);
116+
deleteChain.add(delete);
115117

116-
SqlRenderer renderer = SqlRenderer.create(renderContextFactory.createRenderContext());
117-
return deleteChain.stream().map(d -> new ParametrizedQuery(renderer.render(d), parameterSource));
118-
}
118+
SqlRenderer renderer = SqlRenderer.create(renderContextFactory.createRenderContext());
119119

120-
private void deleteRelations(List<Delete> deleteChain, RelationalPersistentEntity<?> entity, Select parentSelect) {
120+
List<ParametrizedQuery> queries = new ArrayList<>(deleteChain.size());
121+
for (Delete d : deleteChain) {
122+
queries.add(new ParametrizedQuery(renderer.render(d), parameterSource));
123+
}
121124

122-
for (PersistentPropertyPath<RelationalPersistentProperty> path : context
123-
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
125+
return queries;
126+
}
124127

125-
PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(context, path);
128+
private void deleteRelations(List<Delete> deleteChain, RelationalPersistentEntity<?> entity, Select parentSelect) {
126129

127-
// prevent duplication on recursive call
128-
if (path.getLength() > 1 && !extPath.getParentPath().isEmbedded()) {
129-
continue;
130-
}
130+
for (PersistentPropertyPath<RelationalPersistentProperty> path : context
131+
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
131132

132-
if (extPath.isEntity() && !extPath.isEmbedded()) {
133+
AggregatePath aggregatePath = context.getAggregatePath(path);
133134

134-
SqlContext sqlContext = new SqlContext(extPath.getLeafEntity());
135+
// prevent duplication on recursive call
136+
if (path.getLength() > 1 && !aggregatePath.getParentPath().isEmbedded()) {
137+
continue;
138+
}
135139

136-
Condition inCondition = Conditions.in(sqlContext.getTable().column(extPath.getReverseColumnName()),
137-
parentSelect);
140+
if (aggregatePath.isEntity() && !aggregatePath.isEmbedded()) {
138141

139-
Select select = StatementBuilder
140-
.select(sqlContext.getTable().column(extPath.getIdDefiningParentPath().getIdColumnName())
141-
// sqlContext.getIdColumn()
142-
).from(sqlContext.getTable()).where(inCondition).build();
143-
deleteRelations(deleteChain, extPath.getLeafEntity(), select);
142+
SqlContext sqlContext = new SqlContext(aggregatePath.getLeafEntity());
144143

145-
deleteChain.add(StatementBuilder.delete(sqlContext.getTable()).where(inCondition).build());
146-
}
147-
}
148-
}
144+
Condition inCondition = Conditions
145+
.in(sqlContext.getTable().column(aggregatePath.getTableInfo().reverseColumnInfo().name()), parentSelect);
146+
147+
Select select = StatementBuilder.select( //
148+
sqlContext.getTable().column(aggregatePath.getIdDefiningParentPath().getTableInfo().idColumnName()) //
149+
).from(sqlContext.getTable()) //
150+
.where(inCondition) //
151+
.build();
152+
deleteRelations(deleteChain, aggregatePath.getLeafEntity(), select);
153+
154+
deleteChain.add(StatementBuilder.delete(sqlContext.getTable()).where(inCondition).build());
155+
}
156+
}
157+
}
149158
}

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQuery.java

+23-13
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
import java.util.List;
2424
import java.util.function.Function;
2525
import java.util.function.LongSupplier;
26-
import java.util.stream.Stream;
2726
import java.util.function.Supplier;
27+
import java.util.stream.Stream;
2828

2929
import org.springframework.core.convert.converter.Converter;
3030
import org.springframework.data.domain.Pageable;
@@ -58,6 +58,8 @@
5858
* @author Jens Schauder
5959
* @author Diego Krupitza
6060
* @author Mikhail Polivakha
61+
* @author Yunyoung LEE
62+
* @author Nikita Konev
6163
* @since 2.0
6264
*/
6365
public class PartTreeJdbcQuery extends AbstractJdbcQuery {
@@ -123,17 +125,23 @@ private Sort getDynamicSort(RelationalParameterAccessor accessor) {
123125
}
124126

125127
@Override
128+
@Nullable
126129
public Object execute(Object[] values) {
127130

128131
RelationalParametersParameterAccessor accessor = new RelationalParametersParameterAccessor(getQueryMethod(),
129132
values);
130133

131-
if (tree.isDelete()) {
132-
JdbcQueryExecution<?> execution = createModifyingQueryExecutor();
133-
return createDeleteQueries(accessor)
134-
.map(query -> execution.execute(query.getQuery(), query.getParameterSource()))
135-
.reduce((a, b) -> b);
136-
}
134+
if (tree.isDelete()) {
135+
JdbcQueryExecution<?> execution = createModifyingQueryExecutor();
136+
137+
List<ParametrizedQuery> queries = createDeleteQueries(accessor);
138+
Object result = null;
139+
for (ParametrizedQuery query : queries) {
140+
result = execution.execute(query.getQuery(), query.getParameterSource(dialect.getLikeEscaper()));
141+
}
142+
143+
return result;
144+
}
137145

138146
ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor);
139147
ParametrizedQuery query = createQuery(accessor, processor.getReturnedType());
@@ -153,11 +161,13 @@ private JdbcQueryExecution<?> getQueryExecution(ResultProcessor processor,
153161
JdbcQueryExecution<?> queryExecution = getJdbcQueryExecution(extractor, rowMapper);
154162

155163
if (getQueryMethod().isSliceQuery()) {
164+
//noinspection unchecked
156165
return new SliceQueryExecution<>((JdbcQueryExecution<Collection<Object>>) queryExecution, accessor.getPageable());
157166
}
158167

159168
if (getQueryMethod().isPageQuery()) {
160169

170+
//noinspection unchecked
161171
return new PageQueryExecution<>((JdbcQueryExecution<Collection<Object>>) queryExecution, accessor.getPageable(),
162172
() -> {
163173

@@ -186,14 +196,14 @@ ParametrizedQuery createQuery(RelationalParametersParameterAccessor accessor, Re
186196
return queryCreator.createQuery(getDynamicSort(accessor));
187197
}
188198

189-
private Stream<ParametrizedQuery> createDeleteQueries(RelationalParametersParameterAccessor accessor) {
199+
private List<ParametrizedQuery> createDeleteQueries(RelationalParametersParameterAccessor accessor) {
190200

191-
RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation();
201+
RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation();
192202

193-
JdbcDeleteQueryCreator queryCreator = new JdbcDeleteQueryCreator(context, tree, converter, dialect, entityMetadata,
194-
accessor);
195-
return queryCreator.createQuery();
196-
}
203+
JdbcDeleteQueryCreator queryCreator = new JdbcDeleteQueryCreator(context, tree, converter, dialect, entityMetadata,
204+
accessor);
205+
return queryCreator.createQuery();
206+
}
197207

198208
private JdbcQueryExecution<?> getJdbcQueryExecution(@Nullable ResultSetExtractor<Boolean> extractor,
199209
Supplier<RowMapper<?>> rowMapper) {

0 commit comments

Comments
 (0)