From ba0ce49d50cd64cc0ccf86608adefd5b9e01ab5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Wed, 12 Jul 2023 19:38:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Relation=20=E6=89=80=E6=9C=89=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3=E6=94=AF=E6=8C=81=E9=80=9A=E8=BF=87=E4=B8=AD=E9=97=B4?= =?UTF-8?q?=E8=A1=A8=E8=BF=9B=E8=A1=8C=20join=20=E7=9A=84=E5=9C=BA?= =?UTF-8?q?=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/RelationManyToMany.java | 4 +- .../annotation/RelationManyToOne.java | 25 +++- .../annotation/RelationOneToMany.java | 25 +++- .../annotation/RelationOneToOne.java | 25 +++- .../core/relation/AbstractRelation.java | 99 ++++++++++++++-- .../mybatisflex/core/relation/ManyToMany.java | 107 ++--------------- .../mybatisflex/core/relation/ManyToOne.java | 3 + .../mybatisflex/core/relation/OneToMany.java | 66 +++-------- .../mybatisflex/core/relation/OneToOne.java | 3 + .../core/relation/RelationManager.java | 53 +++++++-- .../core/relation/ToManyRelation.java | 77 ++++++++++++ .../core/relation/ToOneRelation.java | 55 +++++---- .../test/relation/onetoone/Account.java | 14 ++- .../test/relation/onetoone/AccountDTO.java | 112 ++++++++++++++++++ .../main/resources/relation/onetoone/data.sql | 12 +- .../resources/relation/onetoone/schema.sql | 11 +- 16 files changed, 480 insertions(+), 211 deletions(-) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToManyRelation.java create mode 100644 mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/relation/onetoone/AccountDTO.java 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 c7ae563b..25891205 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,14 +35,14 @@ public @interface RelationManyToMany { String selfField() default ""; /** - * 目标实体类对应的表的 schema,一般关联数据不是 entity,而是 vo、dto 等需要配置此项 + * 目标实体类对应的表的 schema,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项 * * @return schema 名称 */ String targetSchema() default ""; /** - * 目标实体类对应的表,一般关联数据不是 entity,而是 vo、dto 等需要配置此项 + * 目标实体类对应的表,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项 * * @return 表名 */ 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 c1864ed2..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,14 +35,14 @@ public @interface RelationManyToOne { String selfField(); /** - * 目标实体类对应的表的 schema,一般关联数据不是 entity,而是 vo、dto 等需要配置此项 + * 目标实体类对应的表的 schema,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项 * * @return schema 名称 */ String targetSchema() default ""; /** - * 目标实体类对应的表,一般关联数据不是 entity,而是 vo、dto 等需要配置此项 + * 目标实体类对应的表,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项 * * @return 表名 */ @@ -55,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 dccce6be..53b9cc01 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,14 +35,14 @@ public @interface RelationOneToMany { String selfField() default ""; /** - * 目标实体类对应的表的 schema,一般关联数据不是 entity,而是 vo、dto 等需要配置此项 + * 目标实体类对应的表的 schema,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项 * * @return schema 名称 */ String targetSchema() default ""; /** - * 目标实体类对应的表,一般关联数据不是 entity,而是 vo、dto 等需要配置此项 + * 目标实体类对应的表,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项 * * @return 表名 */ @@ -55,6 +55,27 @@ public @interface RelationOneToMany { */ String targetField(); + /** + * 中间表名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。 + * + * @return 中间表名称 + */ + String joinTable() default ""; + + /** + * 中间表与当前表的关联字段,一对一的关系是通过通过中间表维护时,需要添加此项配置。 + * + * @return 字段名称,列名 + */ + String joinSelfColumn() default ""; + + /** + * 目标表的关联字段名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。 + * + * @return 字段名称和表 + */ + String joinTargetColumn() 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 a881e84c..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,14 +35,14 @@ public @interface RelationOneToOne { String selfField() default ""; /** - * 目标实体类对应的表的 schema,一般关联数据不是 entity,而是 vo、dto 等需要配置此项 + * 目标实体类对应的表的 schema,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项 * * @return schema 名称 */ String targetSchema() default ""; /** - * 目标实体类对应的表,一般关联数据不是 entity,而是 vo、dto 等需要配置此项 + * 目标实体类对应的表,一般情况下,关联数据不是 entity,而是 vo、dto 等需要配置此项 * * @return 表名 */ @@ -55,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..3d6bc4ab 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; @@ -31,6 +31,8 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import static com.mybatisflex.core.query.QueryMethods.column; + abstract class AbstractRelation { protected Class selfEntityClass; @@ -47,14 +49,23 @@ abstract class AbstractRelation { protected TableInfo targetTableInfo; protected FieldWrapper targetFieldWrapper; + protected String joinTable; + protected String joinSelfColumn; + protected String joinTargetColumn; + protected String dataSource; public AbstractRelation(String selfField, String targetSchema, String targetTable, String targetField, + String joinTable, String joinSelfColumn, String joinTargetColumn, String dataSource, Class entityClass, Field relationField) { 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)); @@ -144,13 +155,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); @@ -180,6 +230,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(); @@ -201,21 +255,42 @@ abstract class AbstractRelation { /** - * 把 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())); + } + + 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/ManyToMany.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ManyToMany.java index 75067687..82bd08a8 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,19 @@ 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.joinTable() + , annotation.joinSelfColumn() + , annotation.joinTargetColumn() , annotation.dataSource(), entityClass, relationField); - - this.joinTable = annotation.joinTable(); - this.joinSelfColumn = annotation.joinSelfColumn(); - this.joinTargetColumn = annotation.joinTargetColumn(); - 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())); - } - - if (StringUtil.isNotBlank(orderBy)) { + 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..bf8c5f95 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,20 +16,12 @@ 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 AbstractRelation { +class OneToMany extends ToManyRelation { private String orderBy; private int limit; @@ -39,53 +31,25 @@ class OneToMany extends AbstractRelation { 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); + , annotation.targetField() + , annotation.joinTable() + , annotation.joinSelfColumn() + , annotation.joinTargetColumn() + , 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); - } + @Override + public void customizeQueryWrapper(QueryWrapper queryWrapper) { + if (StringUtil.isNotBlank(orderBy)){ + queryWrapper.orderBy(orderBy); + } - if (limit > 0) { - queryWrapper.limit(limit); - } + if (limit > 0){ + queryWrapper.limit(limit); + } + } - return queryWrapper; - } - - - @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); - } - }); - } } 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..2bd50a95 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToManyRelation.java @@ -0,0 +1,77 @@ +/* + * 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) { + super(selfField, targetSchema, targetTable, targetField, + joinTable, joinSelfColumn, joinTargetColumn, + dataSource, selfEntityClass, relationField); + } + + + @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..a42c1afa 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,42 @@ */ 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); } @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 +58,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..7d72e926 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 @@ -32,7 +32,9 @@ public class Account implements Serializable { private int age; // @RelationOneToOne(selfField = "id", targetField = "accountId") -// @RelationOneToOne(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") @@ -44,11 +46,11 @@ public class Account implements Serializable { // selfField = "id", joinSelfColumn = "account_id", // targetField = "id", joinTargetColumn = "role_id" // ) - @RelationManyToMany( - joinTable = "tb_role_mapping", - joinSelfColumn = "account_id", - joinTargetColumn = "role_id" - ) +// @RelationManyToMany( +// joinTable = "tb_role_mapping", +// joinSelfColumn = "account_id", +// joinTargetColumn = "role_id" +// ) private List 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 +);