|
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