mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-07 00:58:24 +08:00
feat: ToMany Relations add map field support; close #I7KW9U
This commit is contained in:
parent
344d4bb7cc
commit
ca2e03a2f9
@ -67,6 +67,12 @@ public @interface RelationManyToMany {
|
|||||||
*/
|
*/
|
||||||
String targetField() default "";
|
String targetField() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当映射是一个 map 时,使用哪个内容来当做 map 的 Key
|
||||||
|
* @return 指定的列
|
||||||
|
*/
|
||||||
|
String mapKeyField() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 中间表名称。
|
* 中间表名称。
|
||||||
*
|
*
|
||||||
|
|||||||
@ -67,6 +67,12 @@ public @interface RelationOneToMany {
|
|||||||
*/
|
*/
|
||||||
String targetField();
|
String targetField();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当映射是一个 map 时,使用哪个内容来当做 map 的 Key
|
||||||
|
* @return 指定的列
|
||||||
|
*/
|
||||||
|
String mapKeyField() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 中间表名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。
|
* 中间表名称,一对一的关系是通过通过中间表维护时,需要添加此项配置。
|
||||||
*
|
*
|
||||||
|
|||||||
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)) {
|
||||||
|
|||||||
@ -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 +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user