From c13bf3b1085befac968992d1482768d94dcd03f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Thu, 13 Jul 2023 10:10:28 +0800 Subject: [PATCH] refactor: optimize extraCondition --- .../com/mybatisflex/annotation/Condition.java | 90 +++++++++--------- .../annotation/RelationManyToMany.java | 2 +- .../annotation/RelationOneToMany.java | 2 +- .../core/relation/AbstractRelation.java | 89 +++++++++++++----- .../mybatisflex/core/relation/Condition.java | 92 +++++++++---------- .../mybatisflex/core/relation/ManyToMany.java | 2 +- .../mybatisflex/core/relation/OneToMany.java | 2 +- .../core/relation/RelationManager.java | 56 +++++++++-- .../core/relation/ToManyRelation.java | 4 +- .../test/relation/onetoone/Account.java | 4 +- .../test/relation/onetoone/MainTest.java | 8 +- 11 files changed, 213 insertions(+), 138 deletions(-) diff --git a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/Condition.java b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/Condition.java index 078c287e..55c6f0af 100644 --- a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/Condition.java +++ b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/Condition.java @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.mybatisflex.annotation; - -import java.lang.annotation.*; - -/** - * 附件条件。 - * - * @author michael - */ -@Inherited -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.FIELD}) -public @interface Condition { - - /** - * 列名。 - */ - String column(); - - /** - * 逻辑值,> , >= , = , IS NULL, IS NOT NULL 等。 - */ - String logic() default " = "; - - /** - * 值。 - */ - String[] value() default {}; - -} +///* +// * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). +// *

+// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// *

+// * http://www.apache.org/licenses/LICENSE-2.0 +// *

+// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package com.mybatisflex.annotation; +// +//import java.lang.annotation.*; +// +///** +// * 附件条件。 +// * +// * @author michael +// */ +//@Inherited +//@Retention(RetentionPolicy.RUNTIME) +//@Target({ElementType.FIELD}) +//public @interface Condition { +// +// /** +// * 列名。 +// */ +// String column(); +// +// /** +// * 逻辑值,> , >= , = , IS NULL, IS NOT NULL 等。 +// */ +// String logic() default " = "; +// +// /** +// * 值。 +// */ +// String[] value() default {}; +// +//} diff --git a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationManyToMany.java b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationManyToMany.java index c177d55d..5bf1916d 100644 --- a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationManyToMany.java +++ b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationManyToMany.java @@ -91,7 +91,7 @@ public @interface RelationManyToMany { /** * 查询时,追加的额外条件。 */ - Condition[] extraConditions() default {}; + String extraCondition() default ""; /** * 查询排序。 diff --git a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationOneToMany.java b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationOneToMany.java index 5220e5e1..6f4ab060 100644 --- a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationOneToMany.java +++ b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationOneToMany.java @@ -91,7 +91,7 @@ public @interface RelationOneToMany { /** * 查询时,追加的额外条件。 */ - Condition[] extraConditions() default {}; + String extraCondition() default ""; /** * 查询排序。 diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/AbstractRelation.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/AbstractRelation.java index 5b3f2b5d..13b78826 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/AbstractRelation.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/AbstractRelation.java @@ -32,6 +32,7 @@ import static com.mybatisflex.core.query.QueryMethods.column; abstract class AbstractRelation { + protected String name; protected Class selfEntityClass; protected Field relationField; protected FieldWrapper relationFieldWrapper; @@ -51,13 +52,16 @@ abstract class AbstractRelation { protected String joinTargetColumn; protected String dataSource; - protected List extraConditions; + + protected String extraConditionSql; + protected List extraConditionParamKeys; public AbstractRelation(String selfField, String targetSchema, String targetTable, String targetField, String joinTable, String joinSelfColumn, String joinTargetColumn, String dataSource, Class entityClass, Field relationField, - List extraConditions + String extraCondition ) { + this.name = entityClass.getSimpleName()+"."+relationField.getName(); this.selfEntityClass = entityClass; this.relationField = relationField; this.relationFieldWrapper = FieldWrapper.of(entityClass, relationField.getName()); @@ -80,9 +84,64 @@ abstract class AbstractRelation { this.targetFieldWrapper = FieldWrapper.of(targetEntityClass, targetField); this.targetTableInfo = TableInfoFactory.ofEntityClass(targetEntityClass); - this.extraConditions = extraConditions; + + initExtraCondition(extraCondition); } + protected void initExtraCondition(String extraCondition) { + if (StringUtil.isBlank(extraCondition)) { + return; + } + + + List sqlParamKeys = null; + char[] chars = extraCondition.toCharArray(); + StringBuilder sqlBuilder = new StringBuilder(); + sqlBuilder.append(chars[0]); + char prev, current; + boolean keyStart = false; + StringBuilder currentKey = null; + for (int i = 1; i < chars.length; i++) { + prev = chars[i - 1]; + current = chars[i]; + if (prev == ' ' && current == ':') { + keyStart = true; + currentKey = new StringBuilder(); + } else if (keyStart) { + if (current != ' ' && current != ')') { + currentKey.append(current); + } else { + if (sqlParamKeys == null) { + sqlParamKeys = new ArrayList<>(); + } + sqlParamKeys.add(currentKey.toString()); + sqlBuilder.append("?").append(current); + keyStart = false; + currentKey = null; + } + } else { + sqlBuilder.append(current); + } + } + if (keyStart && currentKey != null && currentKey.length() > 0) { + if (sqlParamKeys == null) { + sqlParamKeys = new ArrayList<>(); + } + sqlParamKeys.add(currentKey.toString()); + sqlBuilder.append(" ?"); + } + + this.extraConditionSql = sqlBuilder.toString(); + this.extraConditionParamKeys = sqlParamKeys != null ? sqlParamKeys : Collections.emptyList(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } public Class getSelfEntityClass() { return selfEntityClass; @@ -210,13 +269,6 @@ abstract class AbstractRelation { return values; } - public List getExtraConditions() { - return extraConditions; - } - - public void setExtraConditions(List extraConditions) { - this.extraConditions = extraConditions; - } public Class getMappingType() { return relationFieldWrapper.getMappingType(); @@ -261,17 +313,6 @@ abstract class AbstractRelation { return primaryKeyList.get(0).getProperty(); } - protected static List buildConditions(com.mybatisflex.annotation.Condition[] conditions){ - if (conditions == null || conditions.length == 0){ - return null; - } - List conditionList = new ArrayList<>(); - for (com.mybatisflex.annotation.Condition condition : conditions) { - conditionList.add(new Condition(condition)); - } - return conditionList; - } - /** * 构建查询目标对象的 QueryWrapper @@ -290,10 +331,8 @@ abstract class AbstractRelation { queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).eq(targetValues.iterator().next())); } - if (extraConditions != null) { - for (Condition extraCondition : extraConditions) { - queryWrapper.and(extraCondition.toQueryCondition()); - } + if (StringUtil.isNotBlank(extraConditionSql)) { + queryWrapper.and(extraConditionSql, RelationManager.getExtraConditionParams(extraConditionParamKeys)); } customizeQueryWrapper(queryWrapper); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/Condition.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/Condition.java index f46604a5..a40ef863 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/Condition.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/Condition.java @@ -1,46 +1,46 @@ -/* - * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.mybatisflex.core.relation; - -import com.mybatisflex.core.query.QueryCondition; - -import static com.mybatisflex.core.query.QueryMethods.column; - -class Condition { - - private String column; - private String logic; - private String[] value; - - public Condition(com.mybatisflex.annotation.Condition annotation) { - this.column = annotation.column(); - this.logic = " " + annotation.logic().toUpperCase().trim()+" "; - this.value = annotation.value(); - } - - public QueryCondition toQueryCondition() { - return QueryCondition.create(column(column), logic, getValue()); - } - - public Object getValue() { - if (value == null || value.length == 0) { - return null; - } else if (value.length == 1) { - return value[0]; - } - return value; - } -} +///* +// * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). +// *

+// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// *

+// * http://www.apache.org/licenses/LICENSE-2.0 +// *

+// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package com.mybatisflex.core.relation; +// +//import com.mybatisflex.core.query.QueryCondition; +// +//import static com.mybatisflex.core.query.QueryMethods.column; +// +//class Condition { +// +// private String column; +// private String logic; +// private String[] value; +// +// public Condition(com.mybatisflex.annotation.Condition annotation) { +// this.column = annotation.column(); +// this.logic = " " + annotation.logic().toUpperCase().trim()+" "; +// this.value = annotation.value(); +// } +// +// public QueryCondition toQueryCondition() { +// return QueryCondition.create(column(column), logic, getValue()); +// } +// +// public Object getValue() { +// if (value == null || value.length == 0) { +// return null; +// } else if (value.length == 1) { +// return value[0]; +// } +// return value; +// } +//} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ManyToMany.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ManyToMany.java index 4bcf6ebc..b1c58fa9 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ManyToMany.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ManyToMany.java @@ -34,7 +34,7 @@ class ManyToMany extends ToManyRelation { , annotation.joinSelfColumn() , annotation.joinTargetColumn() , annotation.dataSource(), entityClass, relationField - , buildConditions(annotation.extraConditions())); + , annotation.extraCondition()); this.orderBy = annotation.orderBy(); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/OneToMany.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/OneToMany.java index 68e9aa22..3529d2db 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/OneToMany.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/OneToMany.java @@ -36,7 +36,7 @@ class OneToMany extends ToManyRelation { , annotation.joinSelfColumn() , annotation.joinTargetColumn() , annotation.dataSource(), entityClass, relationField - , buildConditions(annotation.extraConditions())); + , annotation.extraCondition()); this.orderBy = annotation.orderBy(); this.limit = annotation.limit(); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/RelationManager.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/RelationManager.java index f3492e82..604b9007 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/RelationManager.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/RelationManager.java @@ -20,6 +20,7 @@ import com.mybatisflex.annotation.RelationManyToOne; import com.mybatisflex.annotation.RelationOneToMany; import com.mybatisflex.annotation.RelationOneToOne; import com.mybatisflex.core.BaseMapper; +import com.mybatisflex.core.FlexConsts; import com.mybatisflex.core.datasource.DataSourceKey; import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.core.row.Row; @@ -43,7 +44,17 @@ public class RelationManager { } private static Map, List> classRelations = new ConcurrentHashMap<>(); - private static ThreadLocal depthThreadLocal = ThreadLocal.withInitial(() -> 3); + + /** + * 递归查询深度,默认为 2,在一些特殊场景下可以修改这个值 + */ + private static ThreadLocal depthThreadLocal = ThreadLocal.withInitial(() -> 2); + + /** + * 附加条件的查询参数 + */ + private static ThreadLocal> extraConditionParams = new ThreadLocal<>(); + private static List getRelations(Class clazz) { return MapUtil.computeIfAbsent(classRelations, clazz, RelationManager::doGetRelations); @@ -76,14 +87,49 @@ public class RelationManager { return relations; } - public static void setMaxDepth(int maxDepth){ + public static void setMaxDepth(int maxDepth) { depthThreadLocal.set(maxDepth); } - public static int getMaxDepth(){ + public static int getMaxDepth() { return depthThreadLocal.get(); } + public static void setExtraConditionParams(Map params) { + extraConditionParams.set(params); + } + + public static void addExtraConditionParam(String key, String value) { + Map params = extraConditionParams.get(); + if (params == null) { + params = new HashMap<>(); + extraConditionParams.set(params); + } + params.put(key, value); + } + + public static Map getExtraConditionParams() { + return extraConditionParams.get(); + } + + + static Object[] getExtraConditionParams(List keys) { + if (keys == null || keys.isEmpty()) { + return FlexConsts.EMPTY_ARRAY; + } + Map paramMap = extraConditionParams.get(); + if (paramMap == null || paramMap.isEmpty()) { + return new Object[keys.size()]; + } + + Object[] params = new Object[keys.size()]; + for (int i = 0; i < keys.size(); i++) { + params[i] = paramMap.get(keys.get(i)); + } + + return params; + } + public static void queryRelations(BaseMapper mapper, List entities) { doQueryRelations(mapper, entities, 0, depthThreadLocal.get()); @@ -109,8 +155,6 @@ public class RelationManager { try { relations.forEach(relation -> { - Class mappingType = relation.getMappingType(); - Set targetValues; List mappingRows = null; @@ -159,7 +203,7 @@ public class RelationManager { } QueryWrapper queryWrapper = relation.buildQueryWrapper(targetValues); - List targetObjectList = mapper.selectListByQueryAs(queryWrapper, mappingType); + List targetObjectList = mapper.selectListByQueryAs(queryWrapper, relation.getMappingType()); if (CollectionUtil.isNotEmpty(targetObjectList)) { doQueryRelations(mapper, targetObjectList, currentDepth + 1, maxDepth); relation.join(entities, targetObjectList, mappingRows); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToManyRelation.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToManyRelation.java index b86b51e2..662f7812 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToManyRelation.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToManyRelation.java @@ -31,11 +31,11 @@ class ToManyRelation extends AbstractRelation { public ToManyRelation(String selfField, String targetSchema, String targetTable, String targetField, String joinTable, String joinSelfColumn, String joinTargetColumn, String dataSource, Class selfEntityClass, Field relationField, - List extraConditions) { + String extraCondition) { super(selfField, targetSchema, targetTable, targetField, joinTable, joinSelfColumn, joinTargetColumn, dataSource, selfEntityClass, relationField, - extraConditions + extraCondition ); } diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/Account.java b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/Account.java index d1c86261..7269a304 100644 --- a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/Account.java +++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/Account.java @@ -50,9 +50,7 @@ public class Account implements Serializable { joinTable = "tb_role_mapping", joinSelfColumn = "account_id", joinTargetColumn = "role_id", - extraConditions = { - @Condition(column = "name", logic = "is not null"), - } + extraCondition = "(name like '%2%' or id > 1)" ) private List roles; diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/MainTest.java b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/MainTest.java index 1f3203c4..e0e8d09e 100644 --- a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/MainTest.java +++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/MainTest.java @@ -1,15 +1,9 @@ package com.mybatisflex.test.relation.onetoone; -import com.mybatisflex.core.mybatis.FlexConfiguration; -import com.mybatisflex.core.table.TableInfo; -import com.mybatisflex.core.table.TableInfoFactory; - public class MainTest { public static void main(String[] args) { - TableInfo tableInfo = TableInfoFactory.ofEntityClass(Book.class); - tableInfo.buildResultMap(new FlexConfiguration()); - System.out.println(tableInfo); } + }