001/* 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.relation; 017 018import com.mybatisflex.core.exception.FlexExceptions; 019import com.mybatisflex.core.query.QueryColumn; 020import com.mybatisflex.core.query.QueryWrapper; 021import com.mybatisflex.core.row.Row; 022import com.mybatisflex.core.table.IdInfo; 023import com.mybatisflex.core.table.TableInfo; 024import com.mybatisflex.core.table.TableInfoFactory; 025import com.mybatisflex.core.util.ArrayUtil; 026import com.mybatisflex.core.util.ClassUtil; 027import com.mybatisflex.core.util.FieldWrapper; 028import com.mybatisflex.core.util.StringUtil; 029 030import java.lang.reflect.Field; 031import java.util.*; 032 033import static com.mybatisflex.core.query.QueryMethods.column; 034 035abstract class AbstractRelation<SelfEntity> { 036 037 protected String name; 038 protected String simpleName; 039 protected Class<SelfEntity> selfEntityClass; 040 protected Field relationField; 041 protected FieldWrapper relationFieldWrapper; 042 043 protected Field selfField; 044 protected FieldWrapper selfFieldWrapper; 045 046 protected String targetSchema; 047 protected String targetTable; 048 protected Field targetField; 049 protected Class<?> targetEntityClass; 050 protected TableInfo targetTableInfo; 051 protected FieldWrapper targetFieldWrapper; 052 053 protected String joinTable; 054 protected String joinSelfColumn; 055 protected String joinTargetColumn; 056 057 protected String dataSource; 058 059 protected String extraConditionSql; 060 protected List<String> extraConditionParamKeys; 061 062 protected QueryColumn conditionColumn; 063 protected String[] selectColumns; 064 065 public AbstractRelation(String selfField, String targetSchema, String targetTable, String targetField, 066 String joinTable, String joinSelfColumn, String joinTargetColumn, 067 String dataSource, Class<SelfEntity> entityClass, Field relationField, 068 String extraCondition, String[] selectColumns 069 ) { 070 this.name = entityClass.getSimpleName() + "." + relationField.getName(); 071 this.simpleName = relationField.getName(); 072 this.selfEntityClass = entityClass; 073 this.relationField = relationField; 074 this.relationFieldWrapper = FieldWrapper.of(entityClass, relationField.getName()); 075 076 this.joinTable = joinTable; 077 this.joinSelfColumn = joinSelfColumn; 078 this.joinTargetColumn = joinTargetColumn; 079 080 this.dataSource = dataSource; 081 082 this.selfField = ClassUtil.getFirstField(entityClass, field -> field.getName().equals(selfField)); 083 this.selfFieldWrapper = FieldWrapper.of(entityClass, selfField); 084 085 086 this.targetEntityClass = relationFieldWrapper.getMappingType(); 087 this.targetSchema = targetSchema; 088 this.targetTable = targetTable; 089 090 this.targetField = ClassUtil.getFirstField(targetEntityClass, field -> field.getName().equals(targetField)); 091 this.targetFieldWrapper = FieldWrapper.of(targetEntityClass, targetField); 092 093 this.targetTableInfo = TableInfoFactory.ofEntityClass(targetEntityClass); 094 095 this.conditionColumn = column(targetTable, targetTableInfo.getColumnByProperty(this.targetField.getName())); 096 097 if (ArrayUtil.isNotEmpty(selectColumns)) { 098 if (ArrayUtil.contains(selectColumns, conditionColumn.getName())) { 099 this.selectColumns = selectColumns; 100 } else { 101 //需要追加 conditionColumn,因为进行内存 join 的时候,需要用到这个内容进行对比 102 this.selectColumns = ArrayUtil.concat(selectColumns, new String[]{conditionColumn.getName()}); 103 } 104 } 105 106 initExtraCondition(extraCondition); 107 } 108 109 protected void initExtraCondition(String extraCondition) { 110 if (StringUtil.isBlank(extraCondition)) { 111 return; 112 } 113 114 115 List<String> sqlParamKeys = null; 116 char[] chars = extraCondition.toCharArray(); 117 StringBuilder sqlBuilder = new StringBuilder(); 118 sqlBuilder.append(chars[0]); 119 char prev, current; 120 boolean keyStart = false; 121 StringBuilder currentKey = null; 122 for (int i = 1; i < chars.length; i++) { 123 prev = chars[i - 1]; 124 current = chars[i]; 125 if (prev == ' ' && current == ':') { 126 keyStart = true; 127 currentKey = new StringBuilder(); 128 } else if (keyStart) { 129 if (current != ' ' && current != ')') { 130 currentKey.append(current); 131 } else { 132 if (sqlParamKeys == null) { 133 sqlParamKeys = new ArrayList<>(); 134 } 135 sqlParamKeys.add(currentKey.toString()); 136 sqlBuilder.append("?").append(current); 137 keyStart = false; 138 currentKey = null; 139 } 140 } else { 141 sqlBuilder.append(current); 142 } 143 } 144 if (keyStart && currentKey != null && currentKey.length() > 0) { 145 if (sqlParamKeys == null) { 146 sqlParamKeys = new ArrayList<>(); 147 } 148 sqlParamKeys.add(currentKey.toString()); 149 sqlBuilder.append(" ?"); 150 } 151 152 this.extraConditionSql = sqlBuilder.toString(); 153 this.extraConditionParamKeys = sqlParamKeys != null ? sqlParamKeys : Collections.emptyList(); 154 } 155 156 public String getName() { 157 return name; 158 } 159 160 public String getSimpleName() { 161 return simpleName; 162 } 163 164 public Class<SelfEntity> getSelfEntityClass() { 165 return selfEntityClass; 166 } 167 168 public void setSelfEntityClass(Class<SelfEntity> selfEntityClass) { 169 this.selfEntityClass = selfEntityClass; 170 } 171 172 public Field getRelationField() { 173 return relationField; 174 } 175 176 public void setRelationField(Field relationField) { 177 this.relationField = relationField; 178 } 179 180 public FieldWrapper getRelationFieldWrapper() { 181 return relationFieldWrapper; 182 } 183 184 public void setRelationFieldWrapper(FieldWrapper relationFieldWrapper) { 185 this.relationFieldWrapper = relationFieldWrapper; 186 } 187 188 public Field getSelfField() { 189 return selfField; 190 } 191 192 public void setSelfField(Field selfField) { 193 this.selfField = selfField; 194 } 195 196 public FieldWrapper getSelfFieldWrapper() { 197 return selfFieldWrapper; 198 } 199 200 public void setSelfFieldWrapper(FieldWrapper selfFieldWrapper) { 201 this.selfFieldWrapper = selfFieldWrapper; 202 } 203 204 public Field getTargetField() { 205 return targetField; 206 } 207 208 public void setTargetField(Field targetField) { 209 this.targetField = targetField; 210 } 211 212 public Class<?> getTargetEntityClass() { 213 return targetEntityClass; 214 } 215 216 public void setTargetEntityClass(Class<?> targetEntityClass) { 217 this.targetEntityClass = targetEntityClass; 218 } 219 220 public TableInfo getTargetTableInfo() { 221 return targetTableInfo; 222 } 223 224 public void setTargetTableInfo(TableInfo targetTableInfo) { 225 this.targetTableInfo = targetTableInfo; 226 } 227 228 public FieldWrapper getTargetFieldWrapper() { 229 return targetFieldWrapper; 230 } 231 232 public void setTargetFieldWrapper(FieldWrapper targetFieldWrapper) { 233 this.targetFieldWrapper = targetFieldWrapper; 234 } 235 236 public String getTargetSchema() { 237 return targetSchema; 238 } 239 240 public void setTargetSchema(String targetSchema) { 241 this.targetSchema = targetSchema; 242 } 243 244 public String getTargetTable() { 245 return targetTable; 246 } 247 248 public void setTargetTable(String targetTable) { 249 this.targetTable = targetTable; 250 } 251 252 public String getJoinTable() { 253 return joinTable; 254 } 255 256 public void setJoinTable(String joinTable) { 257 this.joinTable = joinTable; 258 } 259 260 public String getJoinSelfColumn() { 261 return joinSelfColumn; 262 } 263 264 public void setJoinSelfColumn(String joinSelfColumn) { 265 this.joinSelfColumn = joinSelfColumn; 266 } 267 268 public String getJoinTargetColumn() { 269 return joinTargetColumn; 270 } 271 272 public void setJoinTargetColumn(String joinTargetColumn) { 273 this.joinTargetColumn = joinTargetColumn; 274 } 275 276 public Set<Object> getSelfFieldValues(List<SelfEntity> selfEntities) { 277 if (selfEntities == null || selfEntities.isEmpty()) { 278 return Collections.emptySet(); 279 } 280 Set<Object> values = new LinkedHashSet<>(); 281 selfEntities.forEach(self -> { 282 Object value = selfFieldWrapper.get(self); 283 if (value != null && !"".equals(value)) { 284 values.add(value); 285 } 286 }); 287 return values; 288 } 289 290 291 public Class<?> getMappingType() { 292 return relationFieldWrapper.getMappingType(); 293 } 294 295 public String getDataSource() { 296 return dataSource; 297 } 298 299 public void setDataSource(String dataSource) { 300 this.dataSource = dataSource; 301 } 302 303 public String getTargetTableWithSchema() { 304 if (StringUtil.isNotBlank(targetTable)) { 305 return StringUtil.isNotBlank(targetSchema) ? targetSchema + "." + targetTable : targetTable; 306 } else { 307 return targetTableInfo.getTableNameWithSchema(); 308 } 309 } 310 311 protected boolean isRelationByMiddleTable() { 312 return StringUtil.isNotBlank(joinTable); 313 } 314 315 316 protected static Class<?> getTargetEntityClass(Class<?> entityClass, Field relationField) { 317 return FieldWrapper.of(entityClass, relationField.getName()).getMappingType(); 318 } 319 320 protected static String getDefaultPrimaryProperty(String key, Class<?> entityClass, String message) { 321 if (StringUtil.isNotBlank(key)) { 322 return key; 323 } 324 325 TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass); 326 List<IdInfo> primaryKeyList = tableInfo.getPrimaryKeyList(); 327 if (primaryKeyList == null || primaryKeyList.size() != 1) { 328 throw FlexExceptions.wrap(message); 329 } 330 331 return primaryKeyList.get(0).getProperty(); 332 } 333 334 335 /** 336 * 构建查询目标对象的 QueryWrapper 337 * 338 * @param targetValues 条件的值 339 * @return QueryWrapper 340 */ 341 public QueryWrapper buildQueryWrapper(Set<Object> targetValues) { 342 QueryWrapper queryWrapper = QueryWrapper.create(); 343 344 if (ArrayUtil.isNotEmpty(selectColumns)) { 345 queryWrapper.select(selectColumns); 346 } 347 348 queryWrapper.from(getTargetTableWithSchema()); 349 350 if (targetValues.size() > 1) { 351 queryWrapper.where(conditionColumn.in(targetValues)); 352 } else { 353 queryWrapper.where(conditionColumn.eq(targetValues.iterator().next())); 354 } 355 356 if (StringUtil.isNotBlank(extraConditionSql)) { 357 queryWrapper.and(extraConditionSql, RelationManager.getExtraConditionParams(extraConditionParamKeys)); 358 } 359 360 customizeQueryWrapper(queryWrapper); 361 362 return queryWrapper; 363 } 364 365 366 /** 367 * 方便子类追加自定义的条件 368 * 369 * @param queryWrapper 查询条件 370 */ 371 public void customizeQueryWrapper(QueryWrapper queryWrapper) { 372 //do thing 373 } 374 375 376 /** 377 * @param selfEntities 当前的实体类列表 378 * @param targetObjectList 查询到的结果 379 * @param mappingRows 中间表的映射数据,非中间表查询的场景下,mappingRows 永远为 null 380 */ 381 public abstract void join(List<SelfEntity> selfEntities, List<?> targetObjectList, List<Row> mappingRows); 382 383}