feat: ToMany Relations add map field support; close #I7KW9U

This commit is contained in:
开源海哥 2023-07-15 10:18:16 +08:00
parent 344d4bb7cc
commit ca2e03a2f9
8 changed files with 118 additions and 49 deletions

View File

@ -67,6 +67,12 @@ public @interface RelationManyToMany {
*/ */
String targetField() default ""; String targetField() default "";
/**
* 当映射是一个 map 使用哪个内容来当做 map Key
* @return 指定的列
*/
String mapKeyField() default "";
/** /**
* 中间表名称 * 中间表名称
* *

View File

@ -67,6 +67,12 @@ public @interface RelationOneToMany {
*/ */
String targetField(); String targetField();
/**
* 当映射是一个 map 使用哪个内容来当做 map Key
* @return 指定的列
*/
String mapKeyField() default "";
/** /**
* 中间表名称一对一的关系是通过通过中间表维护时需要添加此项配置 * 中间表名称一对一的关系是通过通过中间表维护时需要添加此项配置
* *

View File

@ -16,15 +16,11 @@
package com.mybatisflex.core.relation; package com.mybatisflex.core.relation;
import com.mybatisflex.annotation.RelationManyToMany; import com.mybatisflex.annotation.RelationManyToMany;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.util.StringUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
class ManyToMany<SelfEntity> extends ToManyRelation<SelfEntity> { class ManyToMany<SelfEntity> extends ToManyRelation<SelfEntity> {
private String orderBy;
public ManyToMany(RelationManyToMany annotation, Class<SelfEntity> entityClass, Field relationField) { public ManyToMany(RelationManyToMany annotation, Class<SelfEntity> entityClass, Field relationField) {
super(getDefaultPrimaryProperty(annotation.selfField(), entityClass, "@RelationManyToMany.selfField can not be empty in field: \"" + entityClass.getName() + "." + relationField.getName() + "\"") super(getDefaultPrimaryProperty(annotation.selfField(), entityClass, "@RelationManyToMany.selfField can not be empty in field: \"" + entityClass.getName() + "." + relationField.getName() + "\"")
, annotation.targetSchema() , annotation.targetSchema()
@ -35,15 +31,10 @@ class ManyToMany<SelfEntity> extends ToManyRelation<SelfEntity> {
, annotation.joinTargetColumn() , annotation.joinTargetColumn()
, annotation.dataSource(), entityClass, relationField , annotation.dataSource(), entityClass, relationField
, annotation.extraCondition()); , annotation.extraCondition());
this.orderBy = annotation.orderBy(); this.orderBy = annotation.orderBy();
this.setMapKeyField(annotation.mapKeyField());
} }
@Override
public void customizeQueryWrapper(QueryWrapper queryWrapper) {
if (StringUtil.isNotBlank(orderBy)) {
queryWrapper.orderBy(orderBy);
}
}
} }

View File

@ -16,16 +16,11 @@
package com.mybatisflex.core.relation; package com.mybatisflex.core.relation;
import com.mybatisflex.annotation.RelationOneToMany; import com.mybatisflex.annotation.RelationOneToMany;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.util.StringUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
class OneToMany<SelfEntity> extends ToManyRelation<SelfEntity> { class OneToMany<SelfEntity> extends ToManyRelation<SelfEntity> {
private String orderBy;
private int limit;
public OneToMany(RelationOneToMany annotation, Class<SelfEntity> entityClass, Field relationField) { public OneToMany(RelationOneToMany annotation, Class<SelfEntity> entityClass, Field relationField) {
super(getDefaultPrimaryProperty(annotation.selfField(), entityClass, "@RelationOneToMany.selfField can not be empty in field: \"" + entityClass.getName() + "." + relationField.getName() + "\"") super(getDefaultPrimaryProperty(annotation.selfField(), entityClass, "@RelationOneToMany.selfField can not be empty in field: \"" + entityClass.getName() + "." + relationField.getName() + "\"")
@ -37,20 +32,14 @@ class OneToMany<SelfEntity> extends ToManyRelation<SelfEntity> {
, annotation.joinTargetColumn() , annotation.joinTargetColumn()
, annotation.dataSource(), entityClass, relationField , annotation.dataSource(), entityClass, relationField
, annotation.extraCondition()); , annotation.extraCondition());
this.orderBy = annotation.orderBy(); this.orderBy = annotation.orderBy();
this.limit = annotation.limit(); 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);
}
}
} }

View File

@ -15,18 +15,20 @@
*/ */
package com.mybatisflex.core.relation; package com.mybatisflex.core.relation;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row; import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.util.ClassUtil; import com.mybatisflex.core.util.*;
import com.mybatisflex.core.util.MapperUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Collection; import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> { class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
protected String mapKeyField;
protected FieldWrapper mapKeyFieldWrapper;
protected String orderBy;
protected int limit = 0;
public ToManyRelation(String selfField, String targetSchema, String targetTable, String targetField, public ToManyRelation(String selfField, String targetSchema, String targetTable, String targetField,
String joinTable, String joinSelfColumn, String joinTargetColumn, String joinTable, String joinSelfColumn, String joinTargetColumn,
@ -40,6 +42,17 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
} }
@Override
public void customizeQueryWrapper(QueryWrapper queryWrapper) {
if (StringUtil.isNotBlank(orderBy)) {
queryWrapper.orderBy(orderBy);
}
if (limit > 0) {
queryWrapper.limit(limit);
}
}
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@Override @Override
public void join(List<SelfEntity> selfEntities, List<?> targetObjectList, List<Row> mappingRows) { public void join(List<SelfEntity> selfEntities, List<?> targetObjectList, List<Row> mappingRows) {
@ -65,17 +78,50 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
return; return;
} }
Class<?> wrapType = MapperUtil.getWrapType(relationFieldWrapper.getFieldType()); Class<?> fieldType = relationFieldWrapper.getFieldType();
Collection collection = (Collection) ClassUtil.newInstance(wrapType); //map
for (Object targetObject : targetObjectList) { if (Map.class.isAssignableFrom(fieldType)) {
Object targetValue = targetFieldWrapper.get(targetObject); Class<?> wrapType = getMapWrapType(fieldType);
if (targetValue != null && targetMappingValues.contains(targetValue.toString())) { Map map = (Map) ClassUtil.newInstance(wrapType);
collection.add(targetObject); 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<? extends Map> getMapWrapType(Class<?> type) {
if (ClassUtil.canInstance(type.getModifiers())) {
return (Class<? extends Map>) type;
}
return HashMap.class;
}
} }

View File

@ -28,6 +28,7 @@ public class FieldWrapper {
private Class<?> fieldType; private Class<?> fieldType;
private Class<?> mappingType; private Class<?> mappingType;
private Class<?> keyType;
private Method getterMethod; private Method getterMethod;
private Method setterMethod; private Method setterMethod;
@ -64,7 +65,9 @@ public class FieldWrapper {
fieldWrapper = new FieldWrapper(); fieldWrapper = new FieldWrapper();
fieldWrapper.fieldType = findField.getType(); fieldWrapper.fieldType = findField.getType();
fieldWrapper.mappingType = parseMappingType(clazz, findField); initMappingTypeAndKeyType(clazz, findField, fieldWrapper);
fieldWrapper.setterMethod = setter; fieldWrapper.setterMethod = setter;
String[] getterNames = new String[]{"get" + StringUtil.firstCharToUpperCase(fieldName), "is" + StringUtil.firstCharToUpperCase(fieldName)}; String[] getterNames = new String[]{"get" + StringUtil.firstCharToUpperCase(fieldName), "is" + StringUtil.firstCharToUpperCase(fieldName)};
@ -80,7 +83,7 @@ public class FieldWrapper {
return 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); Reflector reflector = Reflectors.of(clazz);
Class<?> fieldType = reflector.getGetterType(field.getName()); Class<?> fieldType = reflector.getGetterType(field.getName());
@ -88,11 +91,17 @@ public class FieldWrapper {
Type genericType = field.getGenericType(); Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) { if (genericType instanceof ParameterizedType) {
Type actualTypeArgument = ((ParameterizedType) genericType).getActualTypeArguments()[0]; 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; return mappingType;
} }
public Class<?> getKeyType() {
return keyType;
}
} }

View File

@ -197,7 +197,7 @@ public class MapperUtil {
if (Collection.class.isAssignableFrom(fieldType)) { if (Collection.class.isAssignableFrom(fieldType)) {
value = mapper.selectListByQueryAs(childQuery, mappingType); value = mapper.selectListByQueryAs(childQuery, mappingType);
if (!fieldType.isAssignableFrom(value.getClass())) { if (!fieldType.isAssignableFrom(value.getClass())) {
fieldType = getWrapType(fieldType); fieldType = getCollectionWrapType(fieldType);
Collection newValue = (Collection) ClassUtil.newInstance(fieldType); Collection newValue = (Collection) ClassUtil.newInstance(fieldType);
newValue.addAll((Collection) value); newValue.addAll((Collection) value);
value = newValue; value = newValue;
@ -225,9 +225,9 @@ public class MapperUtil {
} }
public static Class<?> getWrapType(Class<?> type) { public static Class<? extends Collection> getCollectionWrapType(Class<?> type) {
if (ClassUtil.canInstance(type.getModifiers())) { if (ClassUtil.canInstance(type.getModifiers())) {
return type; return (Class<? extends Collection>) type;
} }
if (List.class.isAssignableFrom(type)) { if (List.class.isAssignableFrom(type)) {

View File

@ -23,6 +23,7 @@ import com.mybatisflex.annotation.Table;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Map;
@Table(value = "tb_account") @Table(value = "tb_account")
public class Account implements Serializable { public class Account implements Serializable {
@ -49,13 +50,23 @@ public class Account implements Serializable {
// selfField = "id", joinSelfColumn = "account_id", // selfField = "id", joinSelfColumn = "account_id",
// targetField = "id", joinTargetColumn = "role_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<Role> roles;
@RelationManyToMany( @RelationManyToMany(
joinTable = "tb_role_mapping", joinTable = "tb_role_mapping",
joinSelfColumn = "account_id", joinSelfColumn = "account_id",
joinTargetColumn = "role_id", joinTargetColumn = "role_id",
extraCondition = "(name like '%2%' or id > 1)" extraCondition = "(name like '%2%' or id > 1)",
mapKeyField = "id"
) )
private List<Role> roles; private Map<Long, Role> rolesMap;
public Long getId() { public Long getId() {
@ -106,6 +117,14 @@ public class Account implements Serializable {
this.roles = roles; this.roles = roles;
} }
public Map<Long, Role> getRolesMap() {
return rolesMap;
}
public void setRolesMap(Map<Long, Role> rolesMap) {
this.rolesMap = rolesMap;
}
@Override @Override
public String toString() { public String toString() {
return "Account{" + return "Account{" +
@ -115,7 +134,7 @@ public class Account implements Serializable {
", idCard=" + idCard + ", idCard=" + idCard +
", books=" + books + ", books=" + books +
", roles=" + roles + ", roles=" + roles +
", rolesMap=" + rolesMap +
'}'; '}';
} }
} }