From ca2e03a2f9c05558fe648adfa17b1322dfca3783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Sat, 15 Jul 2023 10:18:16 +0800 Subject: [PATCH] feat: ToMany Relations add map field support; close #I7KW9U --- .../annotation/RelationManyToMany.java | 6 ++ .../annotation/RelationOneToMany.java | 6 ++ .../mybatisflex/core/relation/ManyToMany.java | 13 +--- .../mybatisflex/core/relation/OneToMany.java | 17 +---- .../core/relation/ToManyRelation.java | 72 +++++++++++++++---- .../mybatisflex/core/util/FieldWrapper.java | 22 ++++-- .../com/mybatisflex/core/util/MapperUtil.java | 6 +- .../test/relation/onetoone/Account.java | 25 ++++++- 8 files changed, 118 insertions(+), 49 deletions(-) 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 5bf1916d..06b86fa4 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 @@ -67,6 +67,12 @@ public @interface RelationManyToMany { */ String targetField() default ""; + /** + * 当映射是一个 map 时,使用哪个内容来当做 map 的 Key + * @return 指定的列 + */ + String mapKeyField() 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 6f4ab060..36c77a03 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 @@ -67,6 +67,12 @@ public @interface RelationOneToMany { */ String targetField(); + /** + * 当映射是一个 map 时,使用哪个内容来当做 map 的 Key + * @return 指定的列 + */ + String mapKeyField() default ""; + /** * 中间表名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。 * 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 b1c58fa9..a57bf92c 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,15 +16,11 @@ package com.mybatisflex.core.relation; import com.mybatisflex.annotation.RelationManyToMany; -import com.mybatisflex.core.query.QueryWrapper; -import com.mybatisflex.core.util.StringUtil; import java.lang.reflect.Field; class ManyToMany extends ToManyRelation { - private String orderBy; - public ManyToMany(RelationManyToMany annotation, Class entityClass, Field relationField) { super(getDefaultPrimaryProperty(annotation.selfField(), entityClass, "@RelationManyToMany.selfField can not be empty in field: \"" + entityClass.getName() + "." + relationField.getName() + "\"") , annotation.targetSchema() @@ -35,15 +31,10 @@ class ManyToMany extends ToManyRelation { , annotation.joinTargetColumn() , annotation.dataSource(), entityClass, relationField , annotation.extraCondition()); + this.orderBy = annotation.orderBy(); + this.setMapKeyField(annotation.mapKeyField()); } - @Override - public void customizeQueryWrapper(QueryWrapper queryWrapper) { - if (StringUtil.isNotBlank(orderBy)) { - queryWrapper.orderBy(orderBy); - } - } - } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/OneToMany.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/OneToMany.java index 3529d2db..4e6afbec 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,16 +16,11 @@ package com.mybatisflex.core.relation; import com.mybatisflex.annotation.RelationOneToMany; -import com.mybatisflex.core.query.QueryWrapper; -import com.mybatisflex.core.util.StringUtil; import java.lang.reflect.Field; class OneToMany extends ToManyRelation { - 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() + "\"") @@ -37,20 +32,14 @@ class OneToMany extends ToManyRelation { , annotation.joinTargetColumn() , annotation.dataSource(), entityClass, relationField , annotation.extraCondition()); + this.orderBy = annotation.orderBy(); this.limit = annotation.limit(); + + this.setMapKeyField(annotation.mapKeyField()); } - @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/ToManyRelation.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToManyRelation.java index cc95dc8d..f855bacc 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToManyRelation.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/relation/ToManyRelation.java @@ -15,18 +15,20 @@ */ package com.mybatisflex.core.relation; +import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.core.row.Row; -import com.mybatisflex.core.util.ClassUtil; -import com.mybatisflex.core.util.MapperUtil; +import com.mybatisflex.core.util.*; import java.lang.reflect.Field; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; class ToManyRelation extends AbstractRelation { + protected String mapKeyField; + protected FieldWrapper mapKeyFieldWrapper; + protected String orderBy; + protected int limit = 0; + public ToManyRelation(String selfField, String targetSchema, String targetTable, String targetField, String joinTable, String joinSelfColumn, String joinTargetColumn, @@ -40,6 +42,17 @@ class ToManyRelation extends AbstractRelation { } + @Override + public void customizeQueryWrapper(QueryWrapper queryWrapper) { + if (StringUtil.isNotBlank(orderBy)) { + queryWrapper.orderBy(orderBy); + } + + if (limit > 0) { + queryWrapper.limit(limit); + } + } + @SuppressWarnings("rawtypes") @Override public void join(List selfEntities, List targetObjectList, List mappingRows) { @@ -65,17 +78,50 @@ class ToManyRelation extends AbstractRelation { 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); + Class fieldType = relationFieldWrapper.getFieldType(); + //map + if (Map.class.isAssignableFrom(fieldType)) { + Class wrapType = getMapWrapType(fieldType); + Map map = (Map) ClassUtil.newInstance(wrapType); + for (Object targetObject : targetObjectList) { + Object targetValue = targetFieldWrapper.get(targetObject); + if (targetValue != null && targetMappingValues.contains(targetValue.toString())) { + Object keyValue = mapKeyFieldWrapper.get(targetObject); + Object needKeyValue = ConvertUtil.convert(keyValue, relationFieldWrapper.getKeyType()); + map.put(needKeyValue, targetObject); + } } + relationFieldWrapper.set(map, selfEntity); + } + //集合 + else { + Class wrapType = MapperUtil.getCollectionWrapType(fieldType); + 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); } - relationFieldWrapper.set(collection, selfEntity); } }); } + public void setMapKeyField(String mapKeyField) { + this.mapKeyField = mapKeyField; + if (StringUtil.isNotBlank(mapKeyField)) { + this.mapKeyFieldWrapper = FieldWrapper.of(targetEntityClass, mapKeyField); + } + } + + public static Class getMapWrapType(Class type) { + if (ClassUtil.canInstance(type.getModifiers())) { + return (Class) type; + } + + return HashMap.class; + } + } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/FieldWrapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/FieldWrapper.java index a896c3af..735470c0 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/FieldWrapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/FieldWrapper.java @@ -28,6 +28,7 @@ public class FieldWrapper { private Class fieldType; private Class mappingType; + private Class keyType; private Method getterMethod; private Method setterMethod; @@ -64,7 +65,9 @@ public class FieldWrapper { fieldWrapper = new FieldWrapper(); fieldWrapper.fieldType = findField.getType(); - fieldWrapper.mappingType = parseMappingType(clazz, findField); + initMappingTypeAndKeyType(clazz, findField, fieldWrapper); + + fieldWrapper.setterMethod = setter; String[] getterNames = new String[]{"get" + StringUtil.firstCharToUpperCase(fieldName), "is" + StringUtil.firstCharToUpperCase(fieldName)}; @@ -80,7 +83,7 @@ public class FieldWrapper { return fieldWrapper; } - private static Class parseMappingType(Class clazz, Field field) { + private static void initMappingTypeAndKeyType(Class clazz, Field field, FieldWrapper fieldWrapper) { Reflector reflector = Reflectors.of(clazz); Class fieldType = reflector.getGetterType(field.getName()); @@ -88,11 +91,17 @@ public class FieldWrapper { Type genericType = field.getGenericType(); if (genericType instanceof ParameterizedType) { Type actualTypeArgument = ((ParameterizedType) genericType).getActualTypeArguments()[0]; - return (Class) actualTypeArgument; + fieldWrapper.mappingType = (Class) actualTypeArgument; } + } else if (Map.class.isAssignableFrom(fieldType)) { + Type genericType = field.getGenericType(); + if (genericType instanceof ParameterizedType) { + fieldWrapper.keyType = (Class) ((ParameterizedType) genericType).getActualTypeArguments()[0]; + fieldWrapper.mappingType = (Class) ((ParameterizedType) genericType).getActualTypeArguments()[1]; + } + } else { + fieldWrapper.mappingType = fieldType; } - - return fieldType; } @@ -120,4 +129,7 @@ public class FieldWrapper { return mappingType; } + public Class getKeyType() { + return keyType; + } } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/MapperUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/MapperUtil.java index 629e2426..b6a3e212 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/MapperUtil.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/MapperUtil.java @@ -197,7 +197,7 @@ public class MapperUtil { if (Collection.class.isAssignableFrom(fieldType)) { value = mapper.selectListByQueryAs(childQuery, mappingType); if (!fieldType.isAssignableFrom(value.getClass())) { - fieldType = getWrapType(fieldType); + fieldType = getCollectionWrapType(fieldType); Collection newValue = (Collection) ClassUtil.newInstance(fieldType); newValue.addAll((Collection) value); value = newValue; @@ -225,9 +225,9 @@ public class MapperUtil { } - public static Class getWrapType(Class type) { + public static Class getCollectionWrapType(Class type) { if (ClassUtil.canInstance(type.getModifiers())) { - return type; + return (Class) type; } if (List.class.isAssignableFrom(type)) { 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 ff56b899..fd515cf0 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 @@ -23,6 +23,7 @@ import com.mybatisflex.annotation.Table; import java.io.Serializable; import java.util.List; +import java.util.Map; @Table(value = "tb_account") public class Account implements Serializable { @@ -49,13 +50,23 @@ 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", +// extraCondition = "(name like '%2%' or id > 1)" +// ) + private List roles; + + @RelationManyToMany( joinTable = "tb_role_mapping", joinSelfColumn = "account_id", joinTargetColumn = "role_id", - extraCondition = "(name like '%2%' or id > 1)" + extraCondition = "(name like '%2%' or id > 1)", + mapKeyField = "id" ) - private List roles; + private Map rolesMap; public Long getId() { @@ -106,6 +117,14 @@ public class Account implements Serializable { this.roles = roles; } + public Map getRolesMap() { + return rolesMap; + } + + public void setRolesMap(Map rolesMap) { + this.rolesMap = rolesMap; + } + @Override public String toString() { return "Account{" + @@ -115,7 +134,7 @@ public class Account implements Serializable { ", idCard=" + idCard + ", books=" + books + ", roles=" + roles + + ", rolesMap=" + rolesMap + '}'; } - }