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 050 protected String valueField; 051 protected boolean onlyQueryValueField; 052 053 protected Class<?> targetEntityClass; 054 protected TableInfo targetTableInfo; 055 protected FieldWrapper targetFieldWrapper; 056 057 protected String joinTable; 058 protected String joinSelfColumn; 059 protected String joinTargetColumn; 060 061 protected String dataSource; 062 063 protected String extraConditionSql; 064 protected List<String> extraConditionParamKeys; 065 066 protected QueryColumn conditionColumn; 067 protected String[] selectColumns; 068 069 public AbstractRelation(String selfField, String targetSchema, String targetTable, String targetField, String valueField, 070 String joinTable, String joinSelfColumn, String joinTargetColumn, 071 String dataSource, Class<SelfEntity> entityClass, Field relationField, 072 String extraCondition, String[] selectColumns 073 ) { 074 this.name = entityClass.getSimpleName() + "." + relationField.getName(); 075 this.simpleName = relationField.getName(); 076 this.selfEntityClass = entityClass; 077 this.relationField = relationField; 078 this.relationFieldWrapper = FieldWrapper.of(entityClass, relationField.getName()); 079 080 this.joinTable = joinTable; 081 this.joinSelfColumn = joinSelfColumn; 082 this.joinTargetColumn = joinTargetColumn; 083 084 this.dataSource = dataSource; 085 086 this.selfField = ClassUtil.getFirstField(entityClass, field -> field.getName().equals(selfField)); 087 this.selfFieldWrapper = FieldWrapper.of(entityClass, selfField); 088 089 //以使用者注解配置为主 090 this.targetTableInfo = StringUtil.isBlank(targetTable) ? TableInfoFactory.ofEntityClass(relationFieldWrapper.getMappingType()) : TableInfoFactory.ofTableName(targetTable); 091 this.targetSchema = targetTableInfo != null ? targetTableInfo.getSchema() : targetSchema; 092 this.targetTable = targetTableInfo != null ? targetTableInfo.getTableName() : targetTable; 093 094 //当指定了 valueField 的时候,一般是 String Integer 等基本数据类型 095 this.targetEntityClass = StringUtil.isNotBlank(valueField) ? targetTableInfo.getEntityClass(): relationFieldWrapper.getMappingType(); 096 097 this.targetField = ClassUtil.getFirstField(targetEntityClass, field -> field.getName().equals(targetField)); 098 this.targetFieldWrapper = FieldWrapper.of(targetEntityClass, targetField); 099 100 this.valueField = valueField; 101 this.onlyQueryValueField = StringUtil.isNotBlank(valueField); 102 103 this.conditionColumn = targetTableInfo == null ? column(targetTable, StringUtil.camelToUnderline(this.targetField.getName())) 104 : column(targetTable, targetTableInfo.getColumnByProperty(this.targetField.getName())); 105 106 if (onlyQueryValueField) { 107 //仅绑定字段时只需要查询关联列和该字段列即可 108 this.selectColumns = new String[]{conditionColumn.getName(), targetTableInfo != null ? targetTableInfo.getColumnByProperty(this.valueField) : StringUtil.camelToUnderline(this.valueField)}; 109 } else { 110 if (ArrayUtil.isNotEmpty(selectColumns)) { 111 if (ArrayUtil.contains(selectColumns, conditionColumn.getName())) { 112 this.selectColumns = selectColumns; 113 } else { 114 //需要追加 conditionColumn,因为进行内存 join 的时候,需要用到这个内容进行对比 115 this.selectColumns = ArrayUtil.concat(selectColumns, new String[]{conditionColumn.getName()}); 116 } 117 } 118 119 } 120 121 initExtraCondition(extraCondition); 122 } 123 124 protected void initExtraCondition(String extraCondition) { 125 if (StringUtil.isBlank(extraCondition)) { 126 return; 127 } 128 129 130 List<String> sqlParamKeys = null; 131 char[] chars = extraCondition.toCharArray(); 132 StringBuilder sqlBuilder = new StringBuilder(); 133 sqlBuilder.append(chars[0]); 134 char prev, current; 135 boolean keyStart = false; 136 StringBuilder currentKey = null; 137 for (int i = 1; i < chars.length; i++) { 138 prev = chars[i - 1]; 139 current = chars[i]; 140 if (prev == ' ' && current == ':') { 141 keyStart = true; 142 currentKey = new StringBuilder(); 143 } else if (keyStart) { 144 if (current != ' ' && current != ')') { 145 currentKey.append(current); 146 } else { 147 if (sqlParamKeys == null) { 148 sqlParamKeys = new ArrayList<>(); 149 } 150 sqlParamKeys.add(currentKey.toString()); 151 sqlBuilder.append("?").append(current); 152 keyStart = false; 153 currentKey = null; 154 } 155 } else { 156 sqlBuilder.append(current); 157 } 158 } 159 if (keyStart && currentKey != null && currentKey.length() > 0) { 160 if (sqlParamKeys == null) { 161 sqlParamKeys = new ArrayList<>(); 162 } 163 sqlParamKeys.add(currentKey.toString()); 164 sqlBuilder.append(" ?"); 165 } 166 167 this.extraConditionSql = sqlBuilder.toString(); 168 this.extraConditionParamKeys = sqlParamKeys != null ? sqlParamKeys : Collections.emptyList(); 169 } 170 171 public String getName() { 172 return name; 173 } 174 175 public String getSimpleName() { 176 return simpleName; 177 } 178 179 public Class<SelfEntity> getSelfEntityClass() { 180 return selfEntityClass; 181 } 182 183 public void setSelfEntityClass(Class<SelfEntity> selfEntityClass) { 184 this.selfEntityClass = selfEntityClass; 185 } 186 187 public Field getRelationField() { 188 return relationField; 189 } 190 191 public void setRelationField(Field relationField) { 192 this.relationField = relationField; 193 } 194 195 public FieldWrapper getRelationFieldWrapper() { 196 return relationFieldWrapper; 197 } 198 199 public void setRelationFieldWrapper(FieldWrapper relationFieldWrapper) { 200 this.relationFieldWrapper = relationFieldWrapper; 201 } 202 203 public Field getSelfField() { 204 return selfField; 205 } 206 207 public void setSelfField(Field selfField) { 208 this.selfField = selfField; 209 } 210 211 public FieldWrapper getSelfFieldWrapper() { 212 return selfFieldWrapper; 213 } 214 215 public void setSelfFieldWrapper(FieldWrapper selfFieldWrapper) { 216 this.selfFieldWrapper = selfFieldWrapper; 217 } 218 219 public Field getTargetField() { 220 return targetField; 221 } 222 223 public void setTargetField(Field targetField) { 224 this.targetField = targetField; 225 } 226 227 public Class<?> getTargetEntityClass() { 228 return targetEntityClass; 229 } 230 231 public void setTargetEntityClass(Class<?> targetEntityClass) { 232 this.targetEntityClass = targetEntityClass; 233 } 234 235 public TableInfo getTargetTableInfo() { 236 return targetTableInfo; 237 } 238 239 public void setTargetTableInfo(TableInfo targetTableInfo) { 240 this.targetTableInfo = targetTableInfo; 241 } 242 243 public FieldWrapper getTargetFieldWrapper() { 244 return targetFieldWrapper; 245 } 246 247 public void setTargetFieldWrapper(FieldWrapper targetFieldWrapper) { 248 this.targetFieldWrapper = targetFieldWrapper; 249 } 250 251 public String getTargetSchema() { 252 return targetSchema; 253 } 254 255 public void setTargetSchema(String targetSchema) { 256 this.targetSchema = targetSchema; 257 } 258 259 public String getTargetTable() { 260 return targetTable; 261 } 262 263 public void setTargetTable(String targetTable) { 264 this.targetTable = targetTable; 265 } 266 267 public String getValueField() { 268 return valueField; 269 } 270 271 public void setValueField(String valueField) { 272 this.valueField = valueField; 273 } 274 275 public boolean isOnlyQueryValueField() { 276 return onlyQueryValueField; 277 } 278 279 public void setOnlyQueryValueField(boolean onlyQueryValueField) { 280 this.onlyQueryValueField = onlyQueryValueField; 281 } 282 283 public String getJoinTable() { 284 return joinTable; 285 } 286 287 public void setJoinTable(String joinTable) { 288 this.joinTable = joinTable; 289 } 290 291 public String getJoinSelfColumn() { 292 return joinSelfColumn; 293 } 294 295 public void setJoinSelfColumn(String joinSelfColumn) { 296 this.joinSelfColumn = joinSelfColumn; 297 } 298 299 public String getJoinTargetColumn() { 300 return joinTargetColumn; 301 } 302 303 public void setJoinTargetColumn(String joinTargetColumn) { 304 this.joinTargetColumn = joinTargetColumn; 305 } 306 307 public Set<Object> getSelfFieldValues(List<SelfEntity> selfEntities) { 308 if (selfEntities == null || selfEntities.isEmpty()) { 309 return Collections.emptySet(); 310 } 311 Set<Object> values = new LinkedHashSet<>(); 312 selfEntities.forEach(self -> { 313 Object value = selfFieldWrapper.get(self); 314 if (value != null && !"".equals(value)) { 315 values.add(value); 316 } 317 }); 318 return values; 319 } 320 321 322 public Class<?> getMappingType() { 323 return relationFieldWrapper.getMappingType(); 324 } 325 326 public String getDataSource() { 327 return dataSource; 328 } 329 330 public void setDataSource(String dataSource) { 331 this.dataSource = dataSource; 332 } 333 334 public String getTargetTableWithSchema() { 335 if (StringUtil.isNotBlank(targetTable)) { 336 return StringUtil.isNotBlank(targetSchema) ? targetSchema + "." + targetTable : targetTable; 337 } else { 338 return targetTableInfo.getTableNameWithSchema(); 339 } 340 } 341 342 protected boolean isRelationByMiddleTable() { 343 return StringUtil.isNotBlank(joinTable); 344 } 345 346 347 protected static Class<?> getTargetEntityClass(Class<?> entityClass, Field relationField) { 348 return FieldWrapper.of(entityClass, relationField.getName()).getMappingType(); 349 } 350 351 protected static String getDefaultPrimaryProperty(String key, Class<?> entityClass, String message) { 352 if (StringUtil.isNotBlank(key)) { 353 return key; 354 } 355 356 TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass); 357 List<IdInfo> primaryKeyList = tableInfo.getPrimaryKeyList(); 358 if (primaryKeyList == null || primaryKeyList.size() != 1) { 359 throw FlexExceptions.wrap(message); 360 } 361 362 return primaryKeyList.get(0).getProperty(); 363 } 364 365 366 /** 367 * 构建查询目标对象的 QueryWrapper 368 * 369 * @param targetValues 条件的值 370 * @return QueryWrapper 371 */ 372 public QueryWrapper buildQueryWrapper(Set<Object> targetValues) { 373 QueryWrapper queryWrapper = QueryWrapper.create(); 374 375 if (ArrayUtil.isNotEmpty(selectColumns)) { 376 queryWrapper.select(selectColumns); 377 } 378 379 queryWrapper.from(getTargetTableWithSchema()); 380 381 if (targetValues.size() > 1) { 382 queryWrapper.where(conditionColumn.in(targetValues)); 383 } else { 384 queryWrapper.where(conditionColumn.eq(targetValues.iterator().next())); 385 } 386 387 if (StringUtil.isNotBlank(extraConditionSql)) { 388 queryWrapper.and(extraConditionSql, RelationManager.getExtraConditionParams(extraConditionParamKeys)); 389 } 390 391 customizeQueryWrapper(queryWrapper); 392 393 return queryWrapper; 394 } 395 396 397 /** 398 * 方便子类追加自定义的条件 399 * 400 * @param queryWrapper 查询条件 401 */ 402 public void customizeQueryWrapper(QueryWrapper queryWrapper) { 403 //do thing 404 } 405 406 407 /** 408 * @param selfEntities 当前的实体类列表 409 * @param targetObjectList 查询到的结果 410 * @param mappingRows 中间表的映射数据,非中间表查询的场景下,mappingRows 永远为 null 411 */ 412 public abstract void join(List<SelfEntity> selfEntities, List<?> targetObjectList, List<Row> mappingRows); 413 414}