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