refactor: optimize extraCondition

This commit is contained in:
开源海哥 2023-07-13 10:10:28 +08:00
parent 04ba382c5c
commit c13bf3b108
11 changed files with 213 additions and 138 deletions

View File

@ -1,45 +1,45 @@
/* ///*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). // * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p> // * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); // * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. // * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at // * You may obtain a copy of the License at
* <p> // * <p>
* http://www.apache.org/licenses/LICENSE-2.0 // * http://www.apache.org/licenses/LICENSE-2.0
* <p> // * <p>
* Unless required by applicable law or agreed to in writing, software // * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, // * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and // * See the License for the specific language governing permissions and
* limitations under the License. // * limitations under the License.
*/ // */
package com.mybatisflex.annotation; //package com.mybatisflex.annotation;
//
import java.lang.annotation.*; //import java.lang.annotation.*;
//
/** ///**
* 附件条件 // * 附件条件
* // *
* @author michael // * @author michael
*/ // */
@Inherited //@Inherited
@Retention(RetentionPolicy.RUNTIME) //@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD}) //@Target({ElementType.FIELD})
public @interface Condition { //public @interface Condition {
//
/** // /**
* 列名 // * 列名
*/ // */
String column(); // String column();
//
/** // /**
* 逻辑值> , >= , = , IS NULL, IS NOT NULL // * 逻辑值> , >= , = , IS NULL, IS NOT NULL
*/ // */
String logic() default " = "; // String logic() default " = ";
//
/** // /**
* // *
*/ // */
String[] value() default {}; // String[] value() default {};
//
} //}

View File

@ -91,7 +91,7 @@ public @interface RelationManyToMany {
/** /**
* 查询时追加的额外条件 * 查询时追加的额外条件
*/ */
Condition[] extraConditions() default {}; String extraCondition() default "";
/** /**
* 查询排序 * 查询排序

View File

@ -91,7 +91,7 @@ public @interface RelationOneToMany {
/** /**
* 查询时追加的额外条件 * 查询时追加的额外条件
*/ */
Condition[] extraConditions() default {}; String extraCondition() default "";
/** /**
* 查询排序 * 查询排序

View File

@ -32,6 +32,7 @@ import static com.mybatisflex.core.query.QueryMethods.column;
abstract class AbstractRelation<SelfEntity> { abstract class AbstractRelation<SelfEntity> {
protected String name;
protected Class<SelfEntity> selfEntityClass; protected Class<SelfEntity> selfEntityClass;
protected Field relationField; protected Field relationField;
protected FieldWrapper relationFieldWrapper; protected FieldWrapper relationFieldWrapper;
@ -51,13 +52,16 @@ abstract class AbstractRelation<SelfEntity> {
protected String joinTargetColumn; protected String joinTargetColumn;
protected String dataSource; protected String dataSource;
protected List<Condition> extraConditions;
protected String extraConditionSql;
protected List<String> extraConditionParamKeys;
public AbstractRelation(String selfField, String targetSchema, String targetTable, String targetField, public AbstractRelation(String selfField, String targetSchema, String targetTable, String targetField,
String joinTable, String joinSelfColumn, String joinTargetColumn, String joinTable, String joinSelfColumn, String joinTargetColumn,
String dataSource, Class<SelfEntity> entityClass, Field relationField, String dataSource, Class<SelfEntity> entityClass, Field relationField,
List<Condition> extraConditions String extraCondition
) { ) {
this.name = entityClass.getSimpleName()+"."+relationField.getName();
this.selfEntityClass = entityClass; this.selfEntityClass = entityClass;
this.relationField = relationField; this.relationField = relationField;
this.relationFieldWrapper = FieldWrapper.of(entityClass, relationField.getName()); this.relationFieldWrapper = FieldWrapper.of(entityClass, relationField.getName());
@ -80,9 +84,64 @@ abstract class AbstractRelation<SelfEntity> {
this.targetFieldWrapper = FieldWrapper.of(targetEntityClass, targetField); this.targetFieldWrapper = FieldWrapper.of(targetEntityClass, targetField);
this.targetTableInfo = TableInfoFactory.ofEntityClass(targetEntityClass); this.targetTableInfo = TableInfoFactory.ofEntityClass(targetEntityClass);
this.extraConditions = extraConditions;
initExtraCondition(extraCondition);
} }
protected void initExtraCondition(String extraCondition) {
if (StringUtil.isBlank(extraCondition)) {
return;
}
List<String> 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<SelfEntity> getSelfEntityClass() { public Class<SelfEntity> getSelfEntityClass() {
return selfEntityClass; return selfEntityClass;
@ -210,13 +269,6 @@ abstract class AbstractRelation<SelfEntity> {
return values; return values;
} }
public List<Condition> getExtraConditions() {
return extraConditions;
}
public void setExtraConditions(List<Condition> extraConditions) {
this.extraConditions = extraConditions;
}
public Class<?> getMappingType() { public Class<?> getMappingType() {
return relationFieldWrapper.getMappingType(); return relationFieldWrapper.getMappingType();
@ -261,17 +313,6 @@ abstract class AbstractRelation<SelfEntity> {
return primaryKeyList.get(0).getProperty(); return primaryKeyList.get(0).getProperty();
} }
protected static List<Condition> buildConditions(com.mybatisflex.annotation.Condition[] conditions){
if (conditions == null || conditions.length == 0){
return null;
}
List<Condition> conditionList = new ArrayList<>();
for (com.mybatisflex.annotation.Condition condition : conditions) {
conditionList.add(new Condition(condition));
}
return conditionList;
}
/** /**
* 构建查询目标对象的 QueryWrapper * 构建查询目标对象的 QueryWrapper
@ -290,10 +331,8 @@ abstract class AbstractRelation<SelfEntity> {
queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).eq(targetValues.iterator().next())); queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).eq(targetValues.iterator().next()));
} }
if (extraConditions != null) { if (StringUtil.isNotBlank(extraConditionSql)) {
for (Condition extraCondition : extraConditions) { queryWrapper.and(extraConditionSql, RelationManager.getExtraConditionParams(extraConditionParamKeys));
queryWrapper.and(extraCondition.toQueryCondition());
}
} }
customizeQueryWrapper(queryWrapper); customizeQueryWrapper(queryWrapper);

View File

@ -1,46 +1,46 @@
/* ///*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). // * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p> // * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); // * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. // * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at // * You may obtain a copy of the License at
* <p> // * <p>
* http://www.apache.org/licenses/LICENSE-2.0 // * http://www.apache.org/licenses/LICENSE-2.0
* <p> // * <p>
* Unless required by applicable law or agreed to in writing, software // * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, // * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and // * See the License for the specific language governing permissions and
* limitations under the License. // * limitations under the License.
*/ // */
package com.mybatisflex.core.relation; //package com.mybatisflex.core.relation;
//
import com.mybatisflex.core.query.QueryCondition; //import com.mybatisflex.core.query.QueryCondition;
//
import static com.mybatisflex.core.query.QueryMethods.column; //import static com.mybatisflex.core.query.QueryMethods.column;
//
class Condition { //class Condition {
//
private String column; // private String column;
private String logic; // private String logic;
private String[] value; // private String[] value;
//
public Condition(com.mybatisflex.annotation.Condition annotation) { // public Condition(com.mybatisflex.annotation.Condition annotation) {
this.column = annotation.column(); // this.column = annotation.column();
this.logic = " " + annotation.logic().toUpperCase().trim()+" "; // this.logic = " " + annotation.logic().toUpperCase().trim()+" ";
this.value = annotation.value(); // this.value = annotation.value();
} // }
//
public QueryCondition toQueryCondition() { // public QueryCondition toQueryCondition() {
return QueryCondition.create(column(column), logic, getValue()); // return QueryCondition.create(column(column), logic, getValue());
} // }
//
public Object getValue() { // public Object getValue() {
if (value == null || value.length == 0) { // if (value == null || value.length == 0) {
return null; // return null;
} else if (value.length == 1) { // } else if (value.length == 1) {
return value[0]; // return value[0];
} // }
return value; // return value;
} // }
} //}

View File

@ -34,7 +34,7 @@ class ManyToMany<SelfEntity> extends ToManyRelation<SelfEntity> {
, annotation.joinSelfColumn() , annotation.joinSelfColumn()
, annotation.joinTargetColumn() , annotation.joinTargetColumn()
, annotation.dataSource(), entityClass, relationField , annotation.dataSource(), entityClass, relationField
, buildConditions(annotation.extraConditions())); , annotation.extraCondition());
this.orderBy = annotation.orderBy(); this.orderBy = annotation.orderBy();
} }

View File

@ -36,7 +36,7 @@ class OneToMany<SelfEntity> extends ToManyRelation<SelfEntity> {
, annotation.joinSelfColumn() , annotation.joinSelfColumn()
, annotation.joinTargetColumn() , annotation.joinTargetColumn()
, annotation.dataSource(), entityClass, relationField , annotation.dataSource(), entityClass, relationField
, buildConditions(annotation.extraConditions())); , annotation.extraCondition());
this.orderBy = annotation.orderBy(); this.orderBy = annotation.orderBy();
this.limit = annotation.limit(); this.limit = annotation.limit();
} }

View File

@ -20,6 +20,7 @@ import com.mybatisflex.annotation.RelationManyToOne;
import com.mybatisflex.annotation.RelationOneToMany; import com.mybatisflex.annotation.RelationOneToMany;
import com.mybatisflex.annotation.RelationOneToOne; import com.mybatisflex.annotation.RelationOneToOne;
import com.mybatisflex.core.BaseMapper; import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.FlexConsts;
import com.mybatisflex.core.datasource.DataSourceKey; import com.mybatisflex.core.datasource.DataSourceKey;
import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row; import com.mybatisflex.core.row.Row;
@ -43,7 +44,17 @@ public class RelationManager {
} }
private static Map<Class<?>, List<AbstractRelation>> classRelations = new ConcurrentHashMap<>(); private static Map<Class<?>, List<AbstractRelation>> classRelations = new ConcurrentHashMap<>();
private static ThreadLocal<Integer> depthThreadLocal = ThreadLocal.withInitial(() -> 3);
/**
* 递归查询深度默认为 2在一些特殊场景下可以修改这个值
*/
private static ThreadLocal<Integer> depthThreadLocal = ThreadLocal.withInitial(() -> 2);
/**
* 附加条件的查询参数
*/
private static ThreadLocal<Map<String, Object>> extraConditionParams = new ThreadLocal<>();
private static List<AbstractRelation> getRelations(Class<?> clazz) { private static List<AbstractRelation> getRelations(Class<?> clazz) {
return MapUtil.computeIfAbsent(classRelations, clazz, RelationManager::doGetRelations); return MapUtil.computeIfAbsent(classRelations, clazz, RelationManager::doGetRelations);
@ -76,14 +87,49 @@ public class RelationManager {
return relations; return relations;
} }
public static void setMaxDepth(int maxDepth){ public static void setMaxDepth(int maxDepth) {
depthThreadLocal.set(maxDepth); depthThreadLocal.set(maxDepth);
} }
public static int getMaxDepth(){ public static int getMaxDepth() {
return depthThreadLocal.get(); return depthThreadLocal.get();
} }
public static void setExtraConditionParams(Map<String, Object> params) {
extraConditionParams.set(params);
}
public static void addExtraConditionParam(String key, String value) {
Map<String, Object> params = extraConditionParams.get();
if (params == null) {
params = new HashMap<>();
extraConditionParams.set(params);
}
params.put(key, value);
}
public static Map<String, Object> getExtraConditionParams() {
return extraConditionParams.get();
}
static Object[] getExtraConditionParams(List<String> keys) {
if (keys == null || keys.isEmpty()) {
return FlexConsts.EMPTY_ARRAY;
}
Map<String, Object> 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 <Entity> void queryRelations(BaseMapper<?> mapper, List<Entity> entities) { public static <Entity> void queryRelations(BaseMapper<?> mapper, List<Entity> entities) {
doQueryRelations(mapper, entities, 0, depthThreadLocal.get()); doQueryRelations(mapper, entities, 0, depthThreadLocal.get());
@ -109,8 +155,6 @@ public class RelationManager {
try { try {
relations.forEach(relation -> { relations.forEach(relation -> {
Class mappingType = relation.getMappingType();
Set<Object> targetValues; Set<Object> targetValues;
List<Row> mappingRows = null; List<Row> mappingRows = null;
@ -159,7 +203,7 @@ public class RelationManager {
} }
QueryWrapper queryWrapper = relation.buildQueryWrapper(targetValues); QueryWrapper queryWrapper = relation.buildQueryWrapper(targetValues);
List<?> targetObjectList = mapper.selectListByQueryAs(queryWrapper, mappingType); List<?> targetObjectList = mapper.selectListByQueryAs(queryWrapper, relation.getMappingType());
if (CollectionUtil.isNotEmpty(targetObjectList)) { if (CollectionUtil.isNotEmpty(targetObjectList)) {
doQueryRelations(mapper, targetObjectList, currentDepth + 1, maxDepth); doQueryRelations(mapper, targetObjectList, currentDepth + 1, maxDepth);
relation.join(entities, targetObjectList, mappingRows); relation.join(entities, targetObjectList, mappingRows);

View File

@ -31,11 +31,11 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
public ToManyRelation(String selfField, String targetSchema, String targetTable, String targetField, public ToManyRelation(String selfField, String targetSchema, String targetTable, String targetField,
String joinTable, String joinSelfColumn, String joinTargetColumn, String joinTable, String joinSelfColumn, String joinTargetColumn,
String dataSource, Class<SelfEntity> selfEntityClass, Field relationField, String dataSource, Class<SelfEntity> selfEntityClass, Field relationField,
List<Condition> extraConditions) { String extraCondition) {
super(selfField, targetSchema, targetTable, targetField, super(selfField, targetSchema, targetTable, targetField,
joinTable, joinSelfColumn, joinTargetColumn, joinTable, joinSelfColumn, joinTargetColumn,
dataSource, selfEntityClass, relationField, dataSource, selfEntityClass, relationField,
extraConditions extraCondition
); );
} }

View File

@ -50,9 +50,7 @@ public class Account implements Serializable {
joinTable = "tb_role_mapping", joinTable = "tb_role_mapping",
joinSelfColumn = "account_id", joinSelfColumn = "account_id",
joinTargetColumn = "role_id", joinTargetColumn = "role_id",
extraConditions = { extraCondition = "(name like '%2%' or id > 1)"
@Condition(column = "name", logic = "is not null"),
}
) )
private List<Role> roles; private List<Role> roles;

View File

@ -1,15 +1,9 @@
package com.mybatisflex.test.relation.onetoone; 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 class MainTest {
public static void main(String[] args) { public static void main(String[] args) {
TableInfo tableInfo = TableInfoFactory.ofEntityClass(Book.class);
tableInfo.buildResultMap(new FlexConfiguration());
System.out.println(tableInfo);
} }
} }