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
new file mode 100644
index 00000000..9ba6eb42
--- /dev/null
+++ b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/Condition.java
@@ -0,0 +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 {};
+
+}
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 915238a9..24427249 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
@@ -35,26 +35,14 @@ public @interface RelationManyToMany {
String selfField() default "";
/**
- *
- * 目标实体类对应的表的 schema 模式。
- *
- *
- * 如果目标实体类没有使用 {@code @Table(schema = "...")} 指定 schema 时,
- * 需要在这里指定对应表的 schema 值。一般关联数据不是 entity 对象,而是 vo、dto
- * 等需要配置此项。
+ * 目标实体类对应的表的 schema,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项
*
* @return schema 名称
*/
String targetSchema() default "";
/**
- *
- * 目标实体类对应的表名。
- *
- *
- * 如果目标实体类没有使用 {@code @Table(value = "...")} 指定表名时,
- * 需要在这里指定对应表的表名。一般关联数据不是 entity 对象,而是 vo、dto
- * 等需要配置此项。
+ * 目标实体类对应的表,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项
*
* @return 表名
*/
@@ -88,6 +76,11 @@ public @interface RelationManyToMany {
*/
String joinTargetColumn();
+ /**
+ * 查询时,追加的额外条件
+ */
+ Condition[] extraConditions() default {};
+
/**
* 查询排序。
*
@@ -102,4 +95,5 @@ public @interface RelationManyToMany {
*/
String dataSource() default "";
+
}
diff --git a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationManyToOne.java b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationManyToOne.java
index 22750e4d..6c406f34 100644
--- a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationManyToOne.java
+++ b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationManyToOne.java
@@ -35,26 +35,14 @@ public @interface RelationManyToOne {
String selfField();
/**
- *
- * 目标实体类对应的表的 schema 模式。
- *
- *
- * 如果目标实体类没有使用 {@code @Table(schema = "...")} 指定 schema 时,
- * 需要在这里指定对应表的 schema 值。一般关联数据不是 entity 对象,而是 vo、dto
- * 等需要配置此项。
+ * 目标实体类对应的表的 schema,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项
*
* @return schema 名称
*/
String targetSchema() default "";
/**
- *
- * 目标实体类对应的表名。
- *
- *
- * 如果目标实体类没有使用 {@code @Table(value = "...")} 指定表名时,
- * 需要在这里指定对应表的表名。一般关联数据不是 entity 对象,而是 vo、dto
- * 等需要配置此项。
+ * 目标实体类对应的表,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项
*
* @return 表名
*/
@@ -67,6 +55,27 @@ public @interface RelationManyToOne {
*/
String targetField() default "";
+ /**
+ * 中间表名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。
+ *
+ * @return 中间表名称
+ */
+ String joinTable() default "";
+
+ /**
+ * 中间表与当前表的关联字段,一对一的关系是通过通过中间表维护时,需要添加此项配置。
+ *
+ * @return 字段名称,列名
+ */
+ String joinSelfColumn() default "";
+
+ /**
+ * 目标表的关联字段名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。
+ *
+ * @return 字段名称和表
+ */
+ String joinTargetColumn() 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 85f5fac4..6fec3ec7 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
@@ -35,26 +35,14 @@ public @interface RelationOneToMany {
String selfField() default "";
/**
- *
- * 目标实体类对应的表的 schema 模式。
- *
- *
- * 如果目标实体类没有使用 {@code @Table(schema = "...")} 指定 schema 时,
- * 需要在这里指定对应表的 schema 值。一般关联数据不是 entity 对象,而是 vo、dto
- * 等需要配置此项。
+ * 目标实体类对应的表的 schema,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项
*
* @return schema 名称
*/
String targetSchema() default "";
/**
- *
- * 目标实体类对应的表名。
- *
- *
- * 如果目标实体类没有使用 {@code @Table(value = "...")} 指定表名时,
- * 需要在这里指定对应表的表名。一般关联数据不是 entity 对象,而是 vo、dto
- * 等需要配置此项。
+ * 目标实体类对应的表,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项
*
* @return 表名
*/
@@ -67,6 +55,32 @@ public @interface RelationOneToMany {
*/
String targetField();
+ /**
+ * 中间表名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。
+ *
+ * @return 中间表名称
+ */
+ String joinTable() default "";
+
+ /**
+ * 中间表与当前表的关联字段,一对一的关系是通过通过中间表维护时,需要添加此项配置。
+ *
+ * @return 字段名称,列名
+ */
+ String joinSelfColumn() default "";
+
+ /**
+ * 目标表的关联字段名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。
+ *
+ * @return 字段名称和表
+ */
+ String joinTargetColumn() default "";
+
+ /**
+ * 查询时,追加的额外条件
+ */
+ Condition[] extraConditions() default {};
+
/**
* 查询排序。
*
diff --git a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationOneToOne.java b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationOneToOne.java
index ab738c85..2d5a5dd3 100644
--- a/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationOneToOne.java
+++ b/mybatis-flex-annotation/src/main/java/com/mybatisflex/annotation/RelationOneToOne.java
@@ -35,26 +35,14 @@ public @interface RelationOneToOne {
String selfField() default "";
/**
- *
- * 目标实体类对应的表的 schema 模式。
- *
- *
- * 如果目标实体类没有使用 {@code @Table(schema = "...")} 指定 schema 时,
- * 需要在这里指定对应表的 schema 值。一般关联数据不是 entity 对象,而是 vo、dto
- * 等需要配置此项。
+ * 目标实体类对应的表的 schema,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项
*
* @return schema 名称
*/
String targetSchema() default "";
/**
- *
- * 目标实体类对应的表名。
- *
- *
- * 如果目标实体类没有使用 {@code @Table(value = "...")} 指定表名时,
- * 需要在这里指定对应表的表名。一般关联数据不是 entity 对象,而是 vo、dto
- * 等需要配置此项。
+ * 目标实体类对应的表,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项
*
* @return 表名
*/
@@ -67,6 +55,27 @@ public @interface RelationOneToOne {
*/
String targetField();
+ /**
+ * 中间表名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。
+ *
+ * @return 中间表名称
+ */
+ String joinTable() default "";
+
+ /**
+ * 中间表与当前表的关联字段,一对一的关系是通过通过中间表维护时,需要添加此项配置。
+ *
+ * @return 字段名称,列名
+ */
+ String joinSelfColumn() default "";
+
+ /**
+ * 目标表的关联字段名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。
+ *
+ * @return 字段名称和表
+ */
+ String joinTargetColumn() 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 5988d572..5b3f2b5d 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
@@ -15,9 +15,9 @@
*/
package com.mybatisflex.core.relation;
-import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.exception.FlexExceptions;
import com.mybatisflex.core.query.QueryWrapper;
+import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.table.IdInfo;
import com.mybatisflex.core.table.TableInfo;
import com.mybatisflex.core.table.TableInfoFactory;
@@ -26,10 +26,9 @@ import com.mybatisflex.core.util.FieldWrapper;
import com.mybatisflex.core.util.StringUtil;
import java.lang.reflect.Field;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
+
+import static com.mybatisflex.core.query.QueryMethods.column;
abstract class AbstractRelation {
@@ -47,14 +46,26 @@ abstract class AbstractRelation {
protected TableInfo targetTableInfo;
protected FieldWrapper targetFieldWrapper;
+ protected String joinTable;
+ protected String joinSelfColumn;
+ protected String joinTargetColumn;
+
protected String dataSource;
+ protected List extraConditions;
public AbstractRelation(String selfField, String targetSchema, String targetTable, String targetField,
- String dataSource, Class entityClass, Field relationField) {
+ String joinTable, String joinSelfColumn, String joinTargetColumn,
+ String dataSource, Class entityClass, Field relationField,
+ List extraConditions
+ ) {
this.selfEntityClass = entityClass;
this.relationField = relationField;
this.relationFieldWrapper = FieldWrapper.of(entityClass, relationField.getName());
+ this.joinTable = joinTable;
+ this.joinSelfColumn = joinSelfColumn;
+ this.joinTargetColumn = joinTargetColumn;
+
this.dataSource = dataSource;
this.selfField = ClassUtil.getFirstField(entityClass, field -> field.getName().equals(selfField));
@@ -69,6 +80,7 @@ abstract class AbstractRelation {
this.targetFieldWrapper = FieldWrapper.of(targetEntityClass, targetField);
this.targetTableInfo = TableInfoFactory.ofEntityClass(targetEntityClass);
+ this.extraConditions = extraConditions;
}
@@ -144,13 +156,52 @@ abstract class AbstractRelation {
this.targetFieldWrapper = targetFieldWrapper;
}
- protected Set getSelfFieldValues(List list) {
- if (list == null || list.isEmpty()) {
+ public String getTargetSchema() {
+ return targetSchema;
+ }
+
+ public void setTargetSchema(String targetSchema) {
+ this.targetSchema = targetSchema;
+ }
+
+ public String getTargetTable() {
+ return targetTable;
+ }
+
+ public void setTargetTable(String targetTable) {
+ this.targetTable = targetTable;
+ }
+
+ public String getJoinTable() {
+ return joinTable;
+ }
+
+ public void setJoinTable(String joinTable) {
+ this.joinTable = joinTable;
+ }
+
+ public String getJoinSelfColumn() {
+ return joinSelfColumn;
+ }
+
+ public void setJoinSelfColumn(String joinSelfColumn) {
+ this.joinSelfColumn = joinSelfColumn;
+ }
+
+ public String getJoinTargetColumn() {
+ return joinTargetColumn;
+ }
+
+ public void setJoinTargetColumn(String joinTargetColumn) {
+ this.joinTargetColumn = joinTargetColumn;
+ }
+
+ public Set getSelfFieldValues(List selfEntities) {
+ if (selfEntities == null || selfEntities.isEmpty()) {
return Collections.emptySet();
}
-
Set values = new LinkedHashSet<>();
- list.forEach(self -> {
+ selfEntities.forEach(self -> {
Object value = selfFieldWrapper.get(self);
if (value != null && !"".equals(value)) {
values.add(value);
@@ -159,6 +210,13 @@ abstract class AbstractRelation {
return values;
}
+ public List getExtraConditions() {
+ return extraConditions;
+ }
+
+ public void setExtraConditions(List extraConditions) {
+ this.extraConditions = extraConditions;
+ }
public Class> getMappingType() {
return relationFieldWrapper.getMappingType();
@@ -180,6 +238,10 @@ abstract class AbstractRelation {
}
}
+ protected boolean isRelationByMiddleTable() {
+ return StringUtil.isNotBlank(joinTable);
+ }
+
protected static Class> getTargetEntityClass(Class> entityClass, Field relationField) {
return FieldWrapper.of(entityClass, relationField.getName()).getMappingType();
@@ -199,23 +261,62 @@ 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;
+ }
+
/**
- * 把 Relations 的配置转换为查询的 QueryWrapper
+ * 构建查询目标对象的 QueryWrapper
*
- * @param selfEntities 当前的实体类
+ * @param targetValues 条件的值
* @return QueryWrapper
*/
- public abstract QueryWrapper toQueryWrapper(List selfEntities);
+ public QueryWrapper buildQueryWrapper(Set targetValues) {
+ QueryWrapper queryWrapper = QueryWrapper.create()
+ .select()
+ .from(getTargetTableWithSchema());
+
+ if (targetValues.size() > 1) {
+ queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).in(targetValues));
+ } else {
+ queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).eq(targetValues.iterator().next()));
+ }
+
+ if (extraConditions != null) {
+ for (Condition extraCondition : extraConditions) {
+ queryWrapper.and(extraCondition.toQueryCondition());
+ }
+ }
+
+ customizeQueryWrapper(queryWrapper);
+
+ return queryWrapper;
+ }
/**
- * 通过 {@link AbstractRelation#toQueryWrapper(List)} 查询到的结果,通过此方法进行内存 join
+ * 方便子类最近自定义的条件
*
+ * @param queryWrapper 查询条件
+ */
+ public void customizeQueryWrapper(QueryWrapper queryWrapper) {
+ //do thing
+ }
+
+
+ /**
* @param selfEntities 当前的实体类列表
* @param targetObjectList 查询到的结果
- * @param mapper 查询的 Mapper
- * @param queriedClasses
+ * @param mappingRows 中间表的映射数据,非中间表查询的场景下,mappingRows 永远为 null
*/
- public abstract void join(List selfEntities, List> targetObjectList, BaseMapper> mapper, Set> queriedClasses);
+ public abstract void join(List selfEntities, List> targetObjectList, List mappingRows);
+
}
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
new file mode 100644
index 00000000..f46604a5
--- /dev/null
+++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/Condition.java
@@ -0,0 +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;
+ }
+}
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 75067687..4bcf6ebc 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
@@ -16,24 +16,12 @@
package com.mybatisflex.core.relation;
import com.mybatisflex.annotation.RelationManyToMany;
-import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.query.QueryWrapper;
-import com.mybatisflex.core.row.Row;
-import com.mybatisflex.core.util.ClassUtil;
-import com.mybatisflex.core.util.CollectionUtil;
-import com.mybatisflex.core.util.MapperUtil;
import com.mybatisflex.core.util.StringUtil;
import java.lang.reflect.Field;
-import java.util.*;
-import static com.mybatisflex.core.query.QueryMethods.column;
-
-class ManyToMany extends AbstractRelation {
-
- private String joinTable;
- private String joinSelfColumn;
- private String joinTargetColumn;
+class ManyToMany extends ToManyRelation {
private String orderBy;
@@ -42,100 +30,20 @@ class ManyToMany extends AbstractRelation {
, annotation.targetSchema()
, annotation.targetTable()
, getDefaultPrimaryProperty(annotation.targetField(), getTargetEntityClass(entityClass, relationField), "@RelationManyToMany.targetField can not be empty in field: \"" + entityClass.getName() + "." + relationField.getName() + "\"")
- , annotation.dataSource(), entityClass, relationField);
-
- this.joinTable = annotation.joinTable();
- this.joinSelfColumn = annotation.joinSelfColumn();
- this.joinTargetColumn = annotation.joinTargetColumn();
-
+ , annotation.joinTable()
+ , annotation.joinSelfColumn()
+ , annotation.joinTargetColumn()
+ , annotation.dataSource(), entityClass, relationField
+ , buildConditions(annotation.extraConditions()));
this.orderBy = annotation.orderBy();
}
- @Override
- public Class> getMappingType() {
- return Row.class;
- }
-
@Override
- public QueryWrapper toQueryWrapper(List selfEntities) {
- Set selfFieldValues = getSelfFieldValues(selfEntities);
- if (selfFieldValues.isEmpty()) {
- return null;
- }
-
- QueryWrapper queryWrapper = QueryWrapper.create().select()
- .from(joinTable);
- if (selfFieldValues.size() > 1) {
- queryWrapper.where(column(joinSelfColumn).in(selfFieldValues));
- } else {
- queryWrapper.where(column(joinSelfColumn).eq(selfFieldValues.iterator().next()));
- }
-
- return queryWrapper;
- }
-
-
- @Override
- public void join(List selfEntities, List> mappingObjectList, BaseMapper> mapper, Set> queriedClasses) {
- List mappingRows = (List) mappingObjectList;
- Set targetValues = new LinkedHashSet<>();
- for (Row row : mappingRows) {
- Object targetValue = row.getIgnoreCase(joinTargetColumn);
- if (targetValue != null) {
- targetValues.add(targetValue);
- }
- }
-
- if (targetValues.isEmpty()) {
- return;
- }
-
- QueryWrapper queryWrapper = QueryWrapper.create().select()
- .from(getTargetTableWithSchema());
- if (targetValues.size() > 1) {
- queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).in(targetValues));
- } else {
- queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).eq(targetValues.iterator().next()));
- }
-
+ public void customizeQueryWrapper(QueryWrapper queryWrapper) {
if (StringUtil.isNotBlank(orderBy)) {
queryWrapper.orderBy(orderBy);
}
-
-
- List> targetObjectList = mapper.selectListByQueryAs(queryWrapper, relationFieldWrapper.getMappingType());
-
- RelationManager.doQueryRelations(mapper, targetObjectList, queriedClasses);
-
- if (CollectionUtil.isNotEmpty(targetObjectList)) {
- selfEntities.forEach(selfEntity -> {
- Object selfValue = selfFieldWrapper.get(selfEntity);
- if (selfValue != null) {
- selfValue = selfValue.toString();
- Set targetMappingValues = new HashSet<>();
- for (Row mappingRow : mappingRows) {
- if (selfValue.equals(String.valueOf(mappingRow.getIgnoreCase(joinSelfColumn)))) {
- Object joinValue = mappingRow.getIgnoreCase(joinTargetColumn);
- if (joinValue != null) {
- targetMappingValues.add(joinValue.toString());
- }
- }
- }
-
- if (!targetMappingValues.isEmpty()) {
- Class> wrapType = MapperUtil.getWrapType(relationFieldWrapper.getFieldType());
- Collection collection = (Collection) ClassUtil.newInstance(wrapType);
- for (Object targetObject : targetObjectList) {
- Object targetValue = targetFieldWrapper.get(targetObject);
- if (targetValue != null && targetMappingValues.contains(targetValue.toString())) {
- collection.add(targetObject);
- }
- }
- relationFieldWrapper.set(collection, selfEntity);
- }
- }
- });
- }
}
+
}
diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ManyToOne.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ManyToOne.java
index 89d0ef7e..06e81f57 100644
--- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ManyToOne.java
+++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ManyToOne.java
@@ -27,6 +27,9 @@ class ManyToOne extends ToOneRelation {
, annotation.targetTable()
, getDefaultPrimaryProperty(annotation.targetField(), getTargetEntityClass(entityClass, relationField)
, "@RelationManyToOne.selfField can not be empty in field: \"" + entityClass.getName() + "." + relationField.getName() + "\"")
+ , annotation.joinTable()
+ , annotation.joinSelfColumn()
+ , annotation.joinTargetColumn()
, annotation.dataSource()
, entityClass
, relationField);
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 800c26e8..68e9aa22 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
@@ -16,76 +16,41 @@
package com.mybatisflex.core.relation;
import com.mybatisflex.annotation.RelationOneToMany;
-import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.query.QueryWrapper;
-import com.mybatisflex.core.util.ClassUtil;
-import com.mybatisflex.core.util.MapperUtil;
import com.mybatisflex.core.util.StringUtil;
import java.lang.reflect.Field;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import static com.mybatisflex.core.query.QueryMethods.column;
+class OneToMany extends ToManyRelation {
-class OneToMany extends AbstractRelation {
-
- private String orderBy;
- private int limit;
+ private String orderBy;
+ private int limit;
- public OneToMany(RelationOneToMany annotation, Class entityClass, Field relationField) {
- super(getDefaultPrimaryProperty(annotation.selfField(), entityClass, "@RelationOneToMany.selfField can not be empty in field: \"" + entityClass.getName() + "." + relationField.getName() + "\"")
+ public OneToMany(RelationOneToMany annotation, Class entityClass, Field relationField) {
+ super(getDefaultPrimaryProperty(annotation.selfField(), entityClass, "@RelationOneToMany.selfField can not be empty in field: \"" + entityClass.getName() + "." + relationField.getName() + "\"")
, annotation.targetSchema()
, annotation.targetTable()
- , annotation.targetField(), annotation.dataSource(), entityClass, relationField);
- this.orderBy = annotation.orderBy();
- this.limit = annotation.limit();
- }
-
- @Override
- public QueryWrapper toQueryWrapper(List selfEntities) {
- Set selfFieldValues = getSelfFieldValues(selfEntities);
- if (selfFieldValues.isEmpty()) {
- return null;
- }
- QueryWrapper queryWrapper = QueryWrapper.create().select()
- .from(getTargetTableWithSchema());
- if (selfFieldValues.size() > 1) {
- queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).in(selfFieldValues));
- } else {
- queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).eq(selfFieldValues.iterator().next()));
- }
-
- if (StringUtil.isNotBlank(orderBy)) {
- queryWrapper.orderBy(orderBy);
- }
-
- if (limit > 0) {
- queryWrapper.limit(limit);
- }
-
- return queryWrapper;
- }
+ , annotation.targetField()
+ , annotation.joinTable()
+ , annotation.joinSelfColumn()
+ , annotation.joinTargetColumn()
+ , annotation.dataSource(), entityClass, relationField
+ , buildConditions(annotation.extraConditions()));
+ this.orderBy = annotation.orderBy();
+ this.limit = annotation.limit();
+ }
- @Override
- public void join(List selfEntities, List> targetObjectList, BaseMapper> mapper, Set> queriedClasses) {
- selfEntities.forEach(selfEntity -> {
- Object selfValue = selfFieldWrapper.get(selfEntity);
- if (selfValue != null) {
- selfValue = selfValue.toString();
- Class> wrapType = MapperUtil.getWrapType(relationFieldWrapper.getFieldType());
- Collection collection = (Collection) ClassUtil.newInstance(wrapType);
- for (Object targetObject : targetObjectList) {
- Object targetValue = targetFieldWrapper.get(targetObject);
- if (targetValue != null && selfValue.equals(targetValue.toString())) {
- collection.add(targetObject);
- }
- }
- relationFieldWrapper.set(collection, selfEntity);
- }
- });
- }
+ @Override
+ public void customizeQueryWrapper(QueryWrapper queryWrapper) {
+ if (StringUtil.isNotBlank(orderBy)) {
+ queryWrapper.orderBy(orderBy);
+ }
+
+ if (limit > 0) {
+ queryWrapper.limit(limit);
+ }
+ }
+
}
diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/OneToOne.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/OneToOne.java
index 45bb9a04..267ffa65 100644
--- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/OneToOne.java
+++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/OneToOne.java
@@ -27,6 +27,9 @@ class OneToOne extends ToOneRelation {
, annotation.targetSchema()
, annotation.targetTable()
, annotation.targetField()
+ , annotation.joinTable()
+ , annotation.joinSelfColumn()
+ , annotation.joinTargetColumn()
, annotation.dataSource()
, entityClass
, relationField);
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 4b72535b..81733943 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
@@ -32,6 +32,8 @@ import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
+import static com.mybatisflex.core.query.QueryMethods.column;
+
/**
* @author michael
*/
@@ -98,8 +100,47 @@ public class RelationManager {
try {
relations.forEach(relation -> {
- QueryWrapper queryWrapper = relation.toQueryWrapper(entities);
- Class> mappingType = relation.getMappingType();
+ Class mappingType = relation.getMappingType();
+ if (queriedClasses.contains(mappingType)) {
+ return;
+ }
+
+ Set targetValues;
+ List mappingRows = null;
+
+ //通过中间表关联查询
+ if (relation.isRelationByMiddleTable()) {
+ targetValues = new HashSet<>();
+ Set selfFieldValues = relation.getSelfFieldValues(entities);
+ QueryWrapper queryWrapper = QueryWrapper.create().select()
+ .from(relation.getJoinTable());
+ if (selfFieldValues.size() > 1) {
+ queryWrapper.where(column(relation.getJoinSelfColumn()).in(selfFieldValues));
+ } else {
+ queryWrapper.where(column(relation.getJoinTargetColumn()).eq(selfFieldValues.iterator().next()));
+ }
+
+ mappingRows = mapper.selectListByQueryAs(queryWrapper, Row.class);
+ if (CollectionUtil.isEmpty(mappingRows)) {
+ return;
+ }
+
+ for (Row mappingData : mappingRows) {
+ Object targetValue = mappingData.getIgnoreCase(relation.getJoinTargetColumn());
+ if (targetValue != null) {
+ targetValues.add(targetValue);
+ }
+ }
+ }
+ //通过外键字段关联查询
+ else {
+ targetValues = relation.getSelfFieldValues(entities);
+ }
+
+ if (CollectionUtil.isEmpty(targetValues)) {
+ return;
+ }
+
String dataSource = relation.getDataSource();
if (StringUtil.isBlank(dataSource) && currentDsKey != null) {
@@ -111,13 +152,11 @@ public class RelationManager {
DataSourceKey.use(dataSource);
}
+ QueryWrapper queryWrapper = relation.buildQueryWrapper(targetValues);
List> targetObjectList = mapper.selectListByQueryAs(queryWrapper, mappingType);
- if (mappingType != Row.class) {
- doQueryRelations(mapper, targetObjectList, queriedClasses);
- }
-
if (CollectionUtil.isNotEmpty(targetObjectList)) {
- relation.join(entities, targetObjectList, mapper, queriedClasses);
+ doQueryRelations(mapper, targetObjectList, queriedClasses);
+ relation.join(entities, targetObjectList, mappingRows);
}
} finally {
if (StringUtil.isNotBlank(dataSource)) {
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
new file mode 100644
index 00000000..b86b51e2
--- /dev/null
+++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToManyRelation.java
@@ -0,0 +1,80 @@
+/*
+ * 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.row.Row;
+import com.mybatisflex.core.util.ClassUtil;
+import com.mybatisflex.core.util.MapperUtil;
+
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+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) {
+ super(selfField, targetSchema, targetTable, targetField,
+ joinTable, joinSelfColumn, joinTargetColumn,
+ dataSource, selfEntityClass, relationField,
+ extraConditions
+ );
+ }
+
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public void join(List selfEntities, List> targetObjectList, List mappingRows) {
+ selfEntities.forEach(selfEntity -> {
+ Object selfValue = selfFieldWrapper.get(selfEntity);
+ if (selfValue != null) {
+ selfValue = selfValue.toString();
+ Set targetMappingValues = new HashSet<>();
+ if (mappingRows != null) {
+ for (Row mappingRow : mappingRows) {
+ if (selfValue.equals(String.valueOf(mappingRow.getIgnoreCase(joinSelfColumn)))) {
+ Object joinValue = mappingRow.getIgnoreCase(joinTargetColumn);
+ if (joinValue != null) {
+ targetMappingValues.add(joinValue.toString());
+ }
+ }
+ }
+ } else {
+ targetMappingValues.add((String) selfValue);
+ }
+
+ if (targetMappingValues.isEmpty()) {
+ return;
+ }
+
+ Class> wrapType = MapperUtil.getWrapType(relationFieldWrapper.getFieldType());
+ Collection collection = (Collection) ClassUtil.newInstance(wrapType);
+ for (Object targetObject : targetObjectList) {
+ Object targetValue = targetFieldWrapper.get(targetObject);
+ if (targetValue != null && targetMappingValues.contains(targetValue.toString())) {
+ collection.add(targetObject);
+ }
+ }
+ relationFieldWrapper.set(collection, selfEntity);
+ }
+ });
+ }
+}
diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToOneRelation.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToOneRelation.java
index c356b30e..0eaaa777 100644
--- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToOneRelation.java
+++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToOneRelation.java
@@ -15,50 +15,44 @@
*/
package com.mybatisflex.core.relation;
-import com.mybatisflex.core.BaseMapper;
-import com.mybatisflex.core.query.QueryWrapper;
+import com.mybatisflex.core.row.Row;
import java.lang.reflect.Field;
import java.util.List;
-import java.util.Set;
-
-import static com.mybatisflex.core.query.QueryMethods.column;
class ToOneRelation extends AbstractRelation {
public ToOneRelation(String selfField, String targetSchema, String targetTable, String targetField,
+ String joinTable, String joinSelfColumn, String joinTargetColumn,
String dataSource, Class selfEntityClass, Field relationField) {
- super(selfField, targetSchema, targetTable, targetField, dataSource, selfEntityClass, relationField);
+ super(selfField, targetSchema, targetTable, targetField,
+ joinTable, joinSelfColumn, joinTargetColumn,
+ dataSource, selfEntityClass, relationField,
+ null
+ );
}
@Override
- public QueryWrapper toQueryWrapper(List selfEntities) {
- Set selfFieldValues = getSelfFieldValues(selfEntities);
- if (selfFieldValues.isEmpty()) {
- return null;
- }
- QueryWrapper queryWrapper = QueryWrapper.create().select()
- .from(getTargetTableWithSchema());
- if (selfFieldValues.size() > 1) {
- queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).in(selfFieldValues));
- } else {
- queryWrapper.where(column(targetTableInfo.getColumnByProperty(targetField.getName())).eq(selfFieldValues.iterator().next()));
- }
- return queryWrapper;
- }
-
-
- @Override
- public void join(List selfEntities, List> targetObjectList, BaseMapper> mapper, Set> queriedClasses) {
+ public void join(List selfEntities, List> targetObjectList, List mappingRows) {
selfEntities.forEach(selfEntity -> {
Object selfValue = selfFieldWrapper.get(selfEntity);
if (selfValue != null) {
selfValue = selfValue.toString();
+ String targetMappingValue = null;
+ if (mappingRows != null) {
+ targetMappingValue = getTargetMappingValue(mappingRows, selfValue);
+ if (targetMappingValue == null) {
+ return;
+ }
+ } else {
+ targetMappingValue = (String) selfValue;
+ }
+
for (Object targetObject : targetObjectList) {
Object targetValue = targetFieldWrapper.get(targetObject);
- if (targetValue != null && selfValue.equals(targetValue.toString())) {
+ if (targetValue != null && targetMappingValue.equals(targetValue.toString())) {
relationFieldWrapper.set(targetObject, selfEntity);
break;
}
@@ -66,4 +60,17 @@ class ToOneRelation extends AbstractRelation {
}
});
}
+
+
+ private String getTargetMappingValue(List mappingRows, Object selfValue) {
+ for (Row mappingRow : mappingRows) {
+ if (selfValue.equals(String.valueOf(mappingRow.getIgnoreCase(joinSelfColumn)))) {
+ Object joinValue = mappingRow.getIgnoreCase(joinTargetColumn);
+ if (joinValue != null) {
+ return joinValue.toString();
+ }
+ }
+ }
+ return null;
+ }
}
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 35605974..d1c86261 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
@@ -33,6 +33,8 @@ public class Account implements Serializable {
// @RelationOneToOne(selfField = "id", targetField = "accountId")
// @RelationOneToOne(targetField = "accountId")
+// @RelationManyToOne(joinTable = "tb_idcard_mapping",joinSelfColumn = "account_id",joinTargetColumn = "idcard_id"
+// ,selfField = "id",targetField = "accountId")
private IDCard idCard;
// @RelationOneToMany(selfField = "id", targetField = "accountId")
@@ -45,9 +47,12 @@ public class Account implements Serializable {
// targetField = "id", joinTargetColumn = "role_id"
// )
@RelationManyToMany(
- joinTable = "tb_role_mapping",
- joinSelfColumn = "account_id",
- joinTargetColumn = "role_id"
+ joinTable = "tb_role_mapping",
+ joinSelfColumn = "account_id",
+ joinTargetColumn = "role_id",
+ extraConditions = {
+ @Condition(column = "name", logic = "is not null"),
+ }
)
private List roles;
@@ -103,12 +108,12 @@ public class Account implements Serializable {
@Override
public String toString() {
return "Account{" +
- "id=" + id +
- ", userName='" + userName + '\'' +
- ", age=" + age +
- ", idCard=" + idCard +
- ", books=" + books +
- ", roles=" + roles +
- '}';
+ "id=" + id +
+ ", userName='" + userName + '\'' +
+ ", age=" + age +
+ ", idCard=" + idCard +
+ ", books=" + books +
+ ", roles=" + roles +
+ '}';
}
}
diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/AccountDTO.java b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/AccountDTO.java
new file mode 100644
index 00000000..c097953e
--- /dev/null
+++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/AccountDTO.java
@@ -0,0 +1,112 @@
+/*
+ * 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.test.relation.onetoone;
+
+import com.mybatisflex.annotation.RelationManyToMany;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class AccountDTO implements Serializable {
+
+ private Long id;
+
+ private String userName;
+
+ private int age;
+
+ // @RelationOneToOne(selfField = "id", targetField = "accountId")
+// @RelationOneToOne(targetField = "accountId")
+ private IDCard idCard;
+
+ // @RelationOneToMany(selfField = "id", targetField = "accountId")
+// @RelationOneToMany(targetField = "accountId")
+ private List books;
+
+ // @RelationManyToMany(
+// joinTable = "tb_role_mapping",
+// selfField = "id", joinSelfColumn = "account_id",
+// targetField = "id", joinTargetColumn = "role_id"
+// )
+ @RelationManyToMany(
+ joinTable = "tb_role_mapping",
+ joinSelfColumn = "account_id",
+ joinTargetColumn = "role_id"
+ )
+ private List roles;
+
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public IDCard getIdCard() {
+ return idCard;
+ }
+
+ public void setIdCard(IDCard idCard) {
+ this.idCard = idCard;
+ }
+
+ public List getBooks() {
+ return books;
+ }
+
+ public void setBooks(List books) {
+ this.books = books;
+ }
+
+ public List getRoles() {
+ return roles;
+ }
+
+ public void setRoles(List roles) {
+ this.roles = roles;
+ }
+
+ @Override
+ public String toString() {
+ return "AccountDTO{" +
+ "id=" + id +
+ ", userName='" + userName + '\'' +
+ ", age=" + age +
+ ", idCard=" + idCard +
+ ", books=" + books +
+ ", roles=" + roles +
+ '}';
+ }
+}
diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/resources/relation/onetoone/data.sql b/mybatis-flex-test/mybatis-flex-native-test/src/main/resources/relation/onetoone/data.sql
index 251108f2..f40561f7 100644
--- a/mybatis-flex-test/mybatis-flex-native-test/src/main/resources/relation/onetoone/data.sql
+++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/resources/relation/onetoone/data.sql
@@ -13,6 +13,16 @@ VALUES (1,'0001', '内容1'),
(4,'0004', '内容4'),
(5,'0005', '内容5');
+INSERT INTO tb_idcard_mapping
+VALUES (1,1),
+ (2,2),
+ (3,3),
+ (4,4),
+ (5,5);
+
+
+
+
INSERT INTO tb_book
VALUES (1,1,'图书1', '内容1'),
(2,2,'图书2', '内容2'),
@@ -49,4 +59,4 @@ VALUES (1,0,'顶级菜单1'),
(10,5,'子菜单'),
(10,5,'子菜单'),
(10,9,'子菜单'),
- (10,9,'子菜单');
\ No newline at end of file
+ (10,9,'子菜单');
diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/resources/relation/onetoone/schema.sql b/mybatis-flex-test/mybatis-flex-native-test/src/main/resources/relation/onetoone/schema.sql
index 4f054da6..6c68202a 100644
--- a/mybatis-flex-test/mybatis-flex-native-test/src/main/resources/relation/onetoone/schema.sql
+++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/resources/relation/onetoone/schema.sql
@@ -14,6 +14,15 @@ CREATE TABLE IF NOT EXISTS `tb_idcard`
);
+CREATE TABLE IF NOT EXISTS `tb_idcard_mapping`
+(
+ `account_id` Integer,
+ `idcard_id` Integer
+);
+
+
+
+
CREATE TABLE IF NOT EXISTS `tb_book`
(
`id` INTEGER auto_increment,
@@ -39,4 +48,4 @@ CREATE TABLE IF NOT EXISTS `tb_menu`
`id` INTEGER auto_increment,
`parent_id` INTEGER,
`name` VARCHAR(100)
-);
\ No newline at end of file
+);