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 extraConditionParams.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 doQueryRelations(mapper, entities, 0, depthThreadLocal.get(), ignoreRelations.get(), onlyQueryRelations.get()); 264 clearConfigIfNecessary(); 265 } 266 267 /** 268 * 清除查询配置 269 */ 270 private static void clearConfigIfNecessary() { 271 Boolean autoClearEnable = autoClearConfig.get(); 272 if (autoClearEnable != null && autoClearEnable) { 273 depthThreadLocal.remove(); 274 extraConditionParams.remove(); 275 onlyQueryRelations.remove(); 276 ignoreRelations.remove(); 277 } 278 } 279 280 281 @SuppressWarnings({"rawtypes", "unchecked"}) 282 static <Entity> void doQueryRelations(BaseMapper<?> mapper, List<Entity> entities, int currentDepth, int maxDepth, Set<String> ignoreRelations, Set<String> queryRelations) { 283 if (CollectionUtil.isEmpty(entities)) { 284 return; 285 } 286 287 if (currentDepth >= maxDepth) { 288 return; 289 } 290 291 Class<Entity> entityClass = (Class<Entity>) ClassUtil.getUsefulClass(entities.get(0).getClass()); 292 List<AbstractRelation> relations = getRelations(entityClass); 293 if (relations.isEmpty()) { 294 return; 295 } 296 297 String currentDsKey = DataSourceKey.get(); 298 try { 299 relations.forEach(relation -> { 300 301 //ignore 302 if (ignoreRelations != null && (ignoreRelations.contains(relation.getSimpleName()) 303 || ignoreRelations.contains(relation.getName()))) { 304 return; 305 } 306 307 //only query 308 if (queryRelations != null && !queryRelations.isEmpty() 309 && !queryRelations.contains(relation.getSimpleName()) 310 && !queryRelations.contains(relation.getName())) { 311 return; 312 } 313 314 //注解配置的数据源 315 String configDsKey = relation.getDataSource(); 316 if (StringUtil.isBlank(configDsKey) && currentDsKey != null) { 317 configDsKey = currentDsKey; 318 } 319 320 try { 321 if (StringUtil.isNotBlank(configDsKey)) { 322 DataSourceKey.use(configDsKey); 323 } 324 325 Set<Object> targetValues; 326 List<Row> mappingRows = null; 327 328 //通过中间表关联查询 329 if (relation.isRelationByMiddleTable()) { 330 targetValues = new HashSet<>(); 331 Set selfFieldValues = relation.getSelfFieldValues(entities); 332 QueryWrapper queryWrapper = QueryWrapper.create().select() 333 .from(relation.getJoinTable()); 334 if (selfFieldValues.size() > 1) { 335 queryWrapper.where(column(relation.getJoinSelfColumn()).in(selfFieldValues)); 336 } else { 337 queryWrapper.where(column(relation.getJoinSelfColumn()).eq(selfFieldValues.iterator().next())); 338 } 339 340 mappingRows = mapper.selectListByQueryAs(queryWrapper, Row.class); 341 if (CollectionUtil.isEmpty(mappingRows)) { 342 return; 343 } 344 345 for (Row mappingData : mappingRows) { 346 Object targetValue = mappingData.getIgnoreCase(relation.getJoinTargetColumn()); 347 if (targetValue != null) { 348 targetValues.add(targetValue); 349 } 350 } 351 } 352 //通过外键字段关联查询 353 else { 354 targetValues = relation.getSelfFieldValues(entities); 355 } 356 357 if (CollectionUtil.isEmpty(targetValues)) { 358 return; 359 } 360 361 //仅绑定字段:As目标实体类 不进行字段绑定:As映射类型 362 QueryWrapper queryWrapper = relation.buildQueryWrapper(targetValues); 363 List<?> targetObjectList = mapper.selectListByQueryAs(queryWrapper, relation.isOnlyQueryValueField() ? relation.getTargetEntityClass() : relation.getMappingType()); 364 if (CollectionUtil.isNotEmpty(targetObjectList)) { 365 366 //递归查询 367 doQueryRelations(mapper, targetObjectList, currentDepth + 1, maxDepth, ignoreRelations, queryRelations); 368 369 //进行内存 join 370 relation.join(entities, targetObjectList, mappingRows); 371 } 372 } finally { 373 if (StringUtil.isNotBlank(configDsKey)) { 374 DataSourceKey.clear(); 375 } 376 } 377 }); 378 } finally { 379 if (currentDsKey != null) { 380 DataSourceKey.use(currentDsKey); 381 } 382 } 383 } 384 385}