|
1 | 1 | /* |
2 | | - * Copyright 2020 the original author or authors. |
| 2 | + * Copyright 2020-2024 the original author or authors. |
3 | 3 | * |
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | 5 | * you may not use this file except in compliance with the License. |
|
22 | 22 | import org.springframework.data.domain.Sort; |
23 | 23 | import org.springframework.data.jdbc.core.convert.JdbcConverter; |
24 | 24 | import org.springframework.data.jdbc.core.convert.QueryMapper; |
| 25 | +import org.springframework.data.mapping.Parameter; |
25 | 26 | import org.springframework.data.mapping.PersistentPropertyPath; |
26 | 27 | import org.springframework.data.relational.core.dialect.Dialect; |
27 | 28 | 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; |
29 | 30 | import org.springframework.data.relational.core.mapping.RelationalMappingContext; |
30 | 31 | import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; |
31 | 32 | import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; |
|
48 | 49 | import org.springframework.util.Assert; |
49 | 50 |
|
50 | 51 | /** |
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} |
52 | 53 | * from a {@link PartTree}. |
53 | 54 | * |
54 | 55 | * @author Yunyoung LEE |
55 | | - * @since 2.3 |
| 56 | + * @author Nikita Konev |
| 57 | + * @since 3.5 |
56 | 58 | */ |
57 | | -class JdbcDeleteQueryCreator extends RelationalQueryCreator<Stream<ParametrizedQuery>> { |
| 59 | +class JdbcDeleteQueryCreator extends RelationalQueryCreator<List<ParametrizedQuery>> { |
58 | 60 |
|
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; |
63 | 65 |
|
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) { |
78 | 79 |
|
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); |
82 | 81 |
|
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"); |
84 | 85 |
|
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 | + } |
89 | 91 |
|
90 | | - @Override |
91 | | - protected Stream<ParametrizedQuery> complete(@Nullable Criteria criteria, Sort sort) { |
| 92 | + @Override |
| 93 | + protected List<ParametrizedQuery> complete(@Nullable Criteria criteria, Sort sort) { |
92 | 94 |
|
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(); |
96 | 98 |
|
97 | | - SqlContext sqlContext = new SqlContext(entity); |
| 99 | + SqlContext sqlContext = new SqlContext(entity); |
98 | 100 |
|
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); |
101 | 103 |
|
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(); |
105 | 107 |
|
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); |
109 | 111 |
|
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(); |
113 | 115 |
|
114 | | - deleteChain.add(delete); |
| 116 | + deleteChain.add(delete); |
115 | 117 |
|
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()); |
119 | 119 |
|
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 | + } |
121 | 124 |
|
122 | | - for (PersistentPropertyPath<RelationalPersistentProperty> path : context |
123 | | - .findPersistentPropertyPaths(entity.getType(), p -> true)) { |
| 125 | + return queries; |
| 126 | + } |
124 | 127 |
|
125 | | - PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(context, path); |
| 128 | + private void deleteRelations(List<Delete> deleteChain, RelationalPersistentEntity<?> entity, Select parentSelect) { |
126 | 129 |
|
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)) { |
131 | 132 |
|
132 | | - if (extPath.isEntity() && !extPath.isEmbedded()) { |
| 133 | + AggregatePath aggregatePath = context.getAggregatePath(path); |
133 | 134 |
|
134 | | - SqlContext sqlContext = new SqlContext(extPath.getLeafEntity()); |
| 135 | + // prevent duplication on recursive call |
| 136 | + if (path.getLength() > 1 && !aggregatePath.getParentPath().isEmbedded()) { |
| 137 | + continue; |
| 138 | + } |
135 | 139 |
|
136 | | - Condition inCondition = Conditions.in(sqlContext.getTable().column(extPath.getReverseColumnName()), |
137 | | - parentSelect); |
| 140 | + if (aggregatePath.isEntity() && !aggregatePath.isEmbedded()) { |
138 | 141 |
|
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()); |
144 | 143 |
|
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 | + } |
149 | 158 | } |
0 commit comments