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).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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).
// * <p>
// * 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
// * <p>
// * http://www.apache.org/licenses/LICENSE-2.0
// * <p>
// * 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 {};
//
//}

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> {
protected String name;
protected Class<SelfEntity> selfEntityClass;
protected Field relationField;
protected FieldWrapper relationFieldWrapper;
@ -51,13 +52,16 @@ abstract class AbstractRelation<SelfEntity> {
protected String joinTargetColumn;
protected String dataSource;
protected List<Condition> extraConditions;
protected String extraConditionSql;
protected List<String> extraConditionParamKeys;
public AbstractRelation(String selfField, String targetSchema, String targetTable, String targetField,
String joinTable, String joinSelfColumn, String joinTargetColumn,
String dataSource, Class<SelfEntity> entityClass, Field relationField,
List<Condition> 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<SelfEntity> {
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<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() {
return selfEntityClass;
@ -210,13 +269,6 @@ abstract class AbstractRelation<SelfEntity> {
return values;
}
public List<Condition> getExtraConditions() {
return extraConditions;
}
public void setExtraConditions(List<Condition> extraConditions) {
this.extraConditions = extraConditions;
}
public Class<?> getMappingType() {
return relationFieldWrapper.getMappingType();
@ -261,17 +313,6 @@ abstract class AbstractRelation<SelfEntity> {
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
@ -290,10 +331,8 @@ abstract class AbstractRelation<SelfEntity> {
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);

View File

@ -1,46 +1,46 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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).
// * <p>
// * 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
// * <p>
// * http://www.apache.org/licenses/LICENSE-2.0
// * <p>
// * 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;
// }
//}

View File

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

View File

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

View File

@ -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<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) {
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<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) {
doQueryRelations(mapper, entities, 0, depthThreadLocal.get());
@ -109,8 +155,6 @@ public class RelationManager {
try {
relations.forEach(relation -> {
Class mappingType = relation.getMappingType();
Set<Object> targetValues;
List<Row> 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);

View File

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

View File

@ -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<Role> roles;

View File

@ -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);
}
}