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.annotation.RelationManyToMany; 019import com.mybatisflex.annotation.RelationManyToOne; 020import com.mybatisflex.annotation.RelationOneToMany; 021import com.mybatisflex.annotation.RelationOneToOne; 022import com.mybatisflex.core.BaseMapper; 023import com.mybatisflex.core.FlexConsts; 024import com.mybatisflex.core.FlexGlobalConfig; 025import com.mybatisflex.core.datasource.DataSourceKey; 026import com.mybatisflex.core.query.QueryWrapper; 027import com.mybatisflex.core.row.Row; 028import com.mybatisflex.core.util.*; 029import org.apache.ibatis.util.MapUtil; 030 031import java.lang.reflect.Field; 032import java.util.*; 033import java.util.concurrent.ConcurrentHashMap; 034 035import static com.mybatisflex.core.query.QueryMethods.column; 036 037/** 038 * @author michael 039 */ 040@SuppressWarnings("rawtypes") 041public class RelationManager { 042 043 private RelationManager() { 044 } 045 046 private static Map<Class<?>, List<AbstractRelation>> classRelations = new ConcurrentHashMap<>(); 047 048 /** 049 * 默认查询深度 050 */ 051 private static int defaultQueryDepth = FlexGlobalConfig.getDefaultConfig().getDefaultRelationQueryDepth(); 052 053 /** 054 * 递归查询深度,默认为 2,在一些特殊场景下可以修改这个值 055 */ 056 private static ThreadLocal<Integer> depthThreadLocal = ThreadLocal.withInitial(() -> defaultQueryDepth); 057 058 /** 059 * 附加条件的查询参数 060 */ 061 private static ThreadLocal<Map<String, Object>> extraConditionParams = new ThreadLocal<>(); 062 063 064 /** 065 * 查询时,可忽略某些已经添加 Relation 注解的属性 066 */ 067 private static ThreadLocal<Set<String>> ignoreRelations = new ThreadLocal<>(); 068 069 070 /** 071 * 查询时,仅查询这个配置的 Relations 072 */ 073 private static ThreadLocal<Set<String>> onlyQueryRelations = new ThreadLocal<>(); 074 075 076 /** 077 * 每次查询是否自动清除 depth extraConditionParams ignoreRelations 的配置 078 */ 079 private static ThreadLocal<Boolean> autoClearConfig = ThreadLocal.withInitial(() -> true); 080 081 082 public static int getDefaultQueryDepth() { 083 return defaultQueryDepth; 084 } 085 086 public static void setDefaultQueryDepth(int defaultQueryDepth) { 087 RelationManager.defaultQueryDepth = defaultQueryDepth; 088 } 089 090 public static void setMaxDepth(int maxDepth) { 091 depthThreadLocal.set(maxDepth); 092 } 093 094 public static int getMaxDepth() { 095 return depthThreadLocal.get(); 096 } 097 098 public static void clearMaxDepth() { 099 depthThreadLocal.remove(); 100 } 101 102 103 public static void setExtraConditionParams(Map<String, Object> params) { 104 extraConditionParams.set(params); 105 } 106 107 public static void addExtraConditionParam(String key, Object value) { 108 Map<String, Object> params = extraConditionParams.get(); 109 if (params == null) { 110 params = new HashMap<>(); 111 extraConditionParams.set(params); 112 } 113 params.put(key, value); 114 } 115 116 public static Map<String, Object> getExtraConditionParams() { 117 return extraConditionParams.get(); 118 } 119 120 public static void clearExtraConditionParams() { 121 extraConditionParams.remove(); 122 } 123 124 125 //////ignore relations ////// 126 public static Set<String> getIgnoreRelations() { 127 return ignoreRelations.get(); 128 } 129 130 public static void setIgnoreRelations(Set<String> ignoreRelations) { 131 RelationManager.ignoreRelations.set(ignoreRelations); 132 } 133 134 135 public static <T> void addIgnoreRelations(LambdaGetter<T>... ignoreRelations) { 136 Set<String> relations = RelationManager.ignoreRelations.get(); 137 if (relations == null) { 138 relations = new HashSet<>(); 139 setIgnoreRelations(relations); 140 } 141 for (LambdaGetter<T> lambdaGetter : ignoreRelations) { 142 String fieldName = LambdaUtil.getFieldName(lambdaGetter); 143 relations.add(fieldName); 144 } 145 } 146 147 public static void addIgnoreRelations(String... ignoreRelations) { 148 Set<String> relations = RelationManager.ignoreRelations.get(); 149 if (relations == null) { 150 relations = new HashSet<>(); 151 setIgnoreRelations(relations); 152 } 153 relations.addAll(Arrays.asList(ignoreRelations)); 154 } 155 156 157 public static void clearIgnoreRelations() { 158 ignoreRelations.remove(); 159 } 160 161 162 //////query relations ////// 163 public static Set<String> getQueryRelations() { 164 return onlyQueryRelations.get(); 165 } 166 167 public static void setQueryRelations(Set<String> queryRelations) { 168 RelationManager.onlyQueryRelations.set(queryRelations); 169 } 170 171 172 public static <T> void addQueryRelations(LambdaGetter<T>... queryRelations) { 173 Set<String> relations = RelationManager.onlyQueryRelations.get(); 174 if (relations == null) { 175 relations = new HashSet<>(); 176 setQueryRelations(relations); 177 } 178 for (LambdaGetter<T> lambdaGetter : queryRelations) { 179 String fieldName = LambdaUtil.getFieldName(lambdaGetter); 180 relations.add(fieldName); 181 } 182 } 183 184 public static void addQueryRelations(String... queryRelations) { 185 Set<String> relations = RelationManager.onlyQueryRelations.get(); 186 if (relations == null) { 187 relations = new HashSet<>(); 188 setQueryRelations(relations); 189 } 190 relations.addAll(Arrays.asList(queryRelations)); 191 } 192 193 194 public static void clearQueryRelations() { 195 onlyQueryRelations.remove(); 196 } 197 198 199 public static void setAutoClearConfig(boolean enable) { 200 autoClearConfig.set(enable); 201 } 202 203 public static boolean getAutoClearConfig() { 204 return autoClearConfig.get(); 205 } 206 207 public static void clearAutoClearConfig() { 208 autoClearConfig.remove(); 209 } 210 211 212 static Object[] getExtraConditionParams(List<String> keys) { 213 if (keys == null || keys.isEmpty()) { 214 return FlexConsts.EMPTY_ARRAY; 215 } 216 Map<String, Object> paramMap = extraConditionParams.get(); 217 if (paramMap == null || paramMap.isEmpty()) { 218 return new Object[keys.size()]; 219 } 220 221 Object[] params = new Object[keys.size()]; 222 for (int i = 0; i < keys.size(); i++) { 223 params[i] = paramMap.get(keys.get(i)); 224 } 225 226 return params; 227 } 228 229 230 private static List<AbstractRelation> getRelations(Class<?> clazz) { 231 return MapUtil.computeIfAbsent(classRelations, clazz, RelationManager::doGetRelations); 232 } 233 234 private static List<AbstractRelation> doGetRelations(Class<?> entityClass) { 235 List<Field> allFields = ClassUtil.getAllFields(entityClass); 236 List<AbstractRelation> relations = new ArrayList<>(); 237 for (Field field : allFields) { 238 RelationManyToMany manyToManyAnnotation = field.getAnnotation(RelationManyToMany.class); 239 if (manyToManyAnnotation != null) { 240 relations.add(new ManyToMany<>(manyToManyAnnotation, entityClass, field)); 241 } 242 243 RelationManyToOne manyToOneAnnotation = field.getAnnotation(RelationManyToOne.class); 244 if (manyToOneAnnotation != null) { 245 relations.add(new ManyToOne<>(manyToOneAnnotation, entityClass, field)); 246 } 247 248 RelationOneToMany oneToManyAnnotation = field.getAnnotation(RelationOneToMany.class); 249 if (oneToManyAnnotation != null) { 250 relations.add(new OneToMany<>(oneToManyAnnotation, entityClass, field)); 251 } 252 253 RelationOneToOne oneToOneAnnotation = field.getAnnotation(RelationOneToOne.class); 254 if (oneToOneAnnotation != null) { 255 relations.add(new OneToOne<>(oneToOneAnnotation, entityClass, field)); 256 } 257 } 258 return relations; 259 } 260 261 262 public static <Entity> void queryRelations(BaseMapper<?> mapper, List<Entity> entities) { 263 try { 264 doQueryRelations(mapper, entities, 0, depthThreadLocal.get(), ignoreRelations.get(), onlyQueryRelations.get()); 265 } finally { 266 clearConfigIfNecessary(); 267 } 268 } 269 270 /** 271 * 清除查询配置 272 */ 273 public static void clearConfigIfNecessary() { 274 Boolean autoClearEnable = autoClearConfig.get(); 275 if (autoClearEnable != null && autoClearEnable) { 276 depthThreadLocal.remove(); 277 extraConditionParams.remove(); 278 onlyQueryRelations.remove(); 279 ignoreRelations.remove(); 280 } 281 } 282 283 284 @SuppressWarnings({"rawtypes", "unchecked"}) 285 static <Entity> void doQueryRelations(BaseMapper<?> mapper, List<Entity> entities, int currentDepth, int maxDepth, Set<String> ignoreRelations, Set<String> queryRelations) { 286 if (CollectionUtil.isEmpty(entities)) { 287 return; 288 } 289 290 if (currentDepth >= maxDepth) { 291 return; 292 } 293 294 Class<Entity> entityClass = (Class<Entity>) ClassUtil.getUsefulClass(entities.get(0).getClass()); 295 List<AbstractRelation> relations = getRelations(entityClass); 296 if (relations.isEmpty()) { 297 return; 298 } 299 300 String currentDsKey = DataSourceKey.get(); 301 try { 302 relations.forEach(relation -> { 303 304 //ignore 305 if (ignoreRelations != null && (ignoreRelations.contains(relation.getSimpleName()) 306 || ignoreRelations.contains(relation.getName()))) { 307 return; 308 } 309 310 //only query 311 if (queryRelations != null && !queryRelations.isEmpty() 312 && !queryRelations.contains(relation.getSimpleName()) 313 && !queryRelations.contains(relation.getName())) { 314 return; 315 } 316 317 //注解配置的数据源 318 String configDsKey = relation.getDataSource(); 319 if (StringUtil.isBlank(configDsKey) && currentDsKey != null) { 320 configDsKey = currentDsKey; 321 } 322 323 try { 324 if (StringUtil.isNotBlank(configDsKey)) { 325 DataSourceKey.use(configDsKey); 326 } 327 328 Set<Object> targetValues; 329 List<Row> mappingRows = null; 330 331 //通过中间表关联查询 332 if (relation.isRelationByMiddleTable()) { 333 334 Set selfFieldValues = relation.getSelfFieldValues(entities); 335 // 当数据对应的字段没有值的情况下,直接返回 336 if (selfFieldValues.isEmpty()) { 337 return; 338 } 339 QueryWrapper queryWrapper = QueryWrapper.create().select() 340 .from(relation.getJoinTable()); 341 if (selfFieldValues.size() > 1) { 342 queryWrapper.where(column(relation.getJoinSelfColumn()).in(selfFieldValues)); 343 } else { 344 queryWrapper.where(column(relation.getJoinSelfColumn()).eq(selfFieldValues.iterator().next())); 345 } 346 347 mappingRows = mapper.selectListByQueryAs(queryWrapper, Row.class); 348 if (CollectionUtil.isEmpty(mappingRows)) { 349 return; 350 } 351 352 targetValues = new HashSet<>(); 353 354 for (Row mappingData : mappingRows) { 355 Object targetValue = mappingData.getIgnoreCase(relation.getJoinTargetColumn()); 356 if (targetValue != null) { 357 targetValues.add(targetValue); 358 } 359 } 360 } 361 //通过外键字段关联查询 362 else { 363 targetValues = relation.getSelfFieldValues(entities); 364 } 365 366 if (CollectionUtil.isEmpty(targetValues)) { 367 return; 368 } 369 370 //仅绑定字段:As目标实体类 不进行字段绑定:As映射类型 371 QueryWrapper queryWrapper = relation.buildQueryWrapper(targetValues); 372 List<?> targetObjectList = mapper.selectListByQueryAs(queryWrapper, relation.isOnlyQueryValueField() ? relation.getTargetEntityClass() : relation.getMappingType()); 373 if (CollectionUtil.isNotEmpty(targetObjectList)) { 374 375 //递归查询 376 doQueryRelations(mapper, targetObjectList, currentDepth + 1, maxDepth, ignoreRelations, queryRelations); 377 378 //进行内存 join 379 relation.join(entities, targetObjectList, mappingRows); 380 } 381 } finally { 382 if (StringUtil.isNotBlank(configDsKey)) { 383 DataSourceKey.clear(); 384 } 385 } 386 }); 387 } finally { 388 if (currentDsKey != null) { 389 DataSourceKey.use(currentDsKey); 390 } 391 } 392 } 393 394}