!350 @RelationOneToMany支持splitBy字符串切割

Merge pull request !350 from Ice/main
This commit is contained in:
Michael Yang 2023-09-26 11:13:39 +00:00 committed by Gitee
commit ab8cbbc07a
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
10 changed files with 535 additions and 1 deletions

View File

@ -230,7 +230,128 @@ public class Account implements Serializable {
> 多对多注解 `@RelationManyToMany` 也是如此。
**splitBy 分割查询** <Badge type="tip" text="v1.6.8" />
`selfField` 是一个 `由字符拼接而成的列表(如 1,2,3)`,那么,我们可以通过配置 `splitBy` 来指定使用 `selfField` 的值根据字符切割后查询,
如下代码所示:
```java 8
@Table(value = "tb_patient")
public class PatientVO1 implements Serializable {
private static final long serialVersionUID = -2298625009592638988L;
/**
* ID
*/
@Id
private Integer patientId;
/**
* 姓名
*/
private String name;
/**
* 所患病症(对应字符串类型) 英文逗号 分割
*/
private String diseaseIds;
/**
* 患者标签(对应数字类型) / 分割
*/
private String tagIds;
@RelationOneToMany(
selfField = "diseaseIds",
splitBy = ",", //使用 , 进行分割
targetTable = "tb_disease", //只获取某个字段值需要填入目标表名
targetField = "diseaseId", //测试目标字段是字符串类型是否正常转换
valueField = "name" //测试只获取某个字段值是否正常
)
private List<String> diseaseNameList;
@RelationOneToMany(
selfField = "tagIds",
splitBy = "/", //使用 / 进行分割
targetField = "tagId" //测试目标字段是数字类型是否正常转换
)
private List<Tag> tagList;
@RelationOneToMany(
selfField = "diseaseIds",
splitBy = ",", //使用 , 进行分割
targetField = "diseaseId", //测试目标字段是字符串类型是否正常转换
mapKeyField = "diseaseId" //测试Map映射
)
private Map<String, Disease> diseaseMap;
//getter setter toString
}
```
进行查询
```java
PatientVO1 patientVO1 = patientMapper.selectOneWithRelationsByQueryAs(QueryWrapper.create().orderBy(PatientVO1::getPatientId, false).limit(1), PatientVO1.class);
System.out.println(JSON.toJSONString(patientVO1));
```
其执行的 SQL 如下:
```sql
SELECT `patient_id`, `name`, `disease_ids`, `tag_ids` FROM `tb_patient` ORDER BY `patient_id` DESC LIMIT 1;
SELECT disease_id, name FROM `tb_disease` WHERE `disease_id` IN ('1', '2', '3', '4');
SELECT `tag_id`, `name` FROM `tb_tag` WHERE `tag_id` IN (1, 2, 3);
SELECT `disease_id`, `name` FROM `tb_disease` WHERE `disease_id` IN ('1', '2', '3', '4');
```
查询结果:
```json
{
"patientId": 4,
"name": "赵六",
"diseaseIds": "1,2,3,4",
"tagIds": "1/2/3",
"diseaseNameList": [
"心脑血管疾病",
"消化系统疾病",
"神经系统疾病",
"免疫系统疾病"
],
"tagList": [
{
"name": "VIP",
"tagId": 1
},
{
"name": "JAVA开发",
"tagId": 2
},
{
"name": "Web开发",
"tagId": 3
}
],
"diseaseMap": {
"1": {
"diseaseId": "1",
"name": "心脑血管疾病"
},
"2": {
"diseaseId": "2",
"name": "消化系统疾病"
},
"3": {
"diseaseId": "3",
"name": "神经系统疾病"
},
"4": {
"diseaseId": "4",
"name": "免疫系统疾病"
}
}
}
```
## 多对一 `@RelationManyToOne`

View File

@ -34,6 +34,12 @@ public @interface RelationOneToMany {
*/
String selfField() default "";
/**
* 当前字段值根据字符串分割
* @return 分割字符串
*/
String splitBy() default "";
/**
* <p>
* 目标实体类对应的表的 schema 模式

View File

@ -35,6 +35,7 @@ class OneToMany<SelfEntity> extends ToManyRelation<SelfEntity> {
, annotation.extraCondition()
, annotation.selectColumns());
this.splitBy = annotation.splitBy();
this.orderBy = annotation.orderBy();
this.limit = annotation.limit();

View File

@ -29,6 +29,8 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
protected FieldWrapper mapKeyFieldWrapper;
protected String orderBy;
protected long limit = 0;
protected String splitBy;
public ToManyRelation(String selfField, String targetSchema, String targetTable, String targetField, String valueField,
@ -42,6 +44,34 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
);
}
/**
* 构建查询目标对象的 QueryWrapper
*
* @param targetValues 条件的值
* @return QueryWrapper
*/
@Override
public QueryWrapper buildQueryWrapper(Set<Object> targetValues) {
if (StringUtil.isNotBlank(splitBy) && CollectionUtil.isNotEmpty(targetValues)) {
Set<Object> newTargetValues = new HashSet<>();
for (Object targetValue : targetValues) {
if (targetValue == null) {
continue;
}
if (!(targetValue instanceof String)) {
throw FlexExceptions.wrap("被切割字段只支持String类型");
}
String[] splitValues = ((String) targetValue).split(splitBy);
for (String splitValue : splitValues) {
//优化分割后的数据类型(防止在数据库查询时候出现隐式转换)
newTargetValues.add(ConvertUtil.convert(splitValue, targetFieldWrapper.getFieldType()));
}
}
targetValues = newTargetValues;
}
return super.buildQueryWrapper(targetValues);
}
@Override
public void customizeQueryWrapper(QueryWrapper queryWrapper) {
@ -72,7 +102,12 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
}
}
} else {
targetMappingValues.add((String) selfValue);
if (StringUtil.isNotBlank(splitBy)) {
String[] splitValues = ((String) selfValue).split(splitBy);
targetMappingValues.addAll(Arrays.asList(splitValues));
} else {
targetMappingValues.add((String) selfValue);
}
}
if (targetMappingValues.isEmpty()) {

View File

@ -0,0 +1,45 @@
package com.mybatisflex.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
/**
* 疾病
*
* @author Ice 2023/09/26
* @version 1.0
*/
@Table(value = "tb_disease")
public class Disease implements Serializable {
private static final long serialVersionUID = -3195530228167432902L;
/**
* ID
*/
@Id(keyType = KeyType.Generator, value = "uuid")
private String diseaseId;
/**
* 疾病名称
*/
private String name;
public String getDiseaseId() {
return diseaseId;
}
public void setDiseaseId(String diseaseId) {
this.diseaseId = diseaseId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,72 @@
package com.mybatisflex.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.activerecord.Model;
import java.io.Serializable;
/**
* 患者信息
*
* @author Ice 2023/09/26
* @version 1.0
*/
@Table(value = "tb_patient")
public class Patient extends Model<Patient> implements Serializable {
private static final long serialVersionUID = 5117723684832788508L;
/**
* ID
*/
@Id
private Integer patientId;
/**
* 姓名
*/
private String name;
/**
* 所患病症(对应字符串类型) 英文逗号 分割
*/
private String diseaseIds;
/**
* 患者标签(对应数字类型) / 分割
*/
private String tagIds;
public Integer getPatientId() {
return patientId;
}
public void setPatientId(Integer patientId) {
this.patientId = patientId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDiseaseIds() {
return diseaseIds;
}
public void setDiseaseIds(String diseaseIds) {
this.diseaseIds = diseaseIds;
}
public String getTagIds() {
return tagIds;
}
public void setTagIds(String tagIds) {
this.tagIds = tagIds;
}
}

View File

@ -0,0 +1,121 @@
package com.mybatisflex.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.RelationOneToMany;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* 患者VO
*
* @author Ice 2023/09/26
* @version 1.0
*/
@Table(value = "tb_patient")
public class PatientVO1 implements Serializable {
private static final long serialVersionUID = -2298625009592638988L;
/**
* ID
*/
@Id
private Integer patientId;
/**
* 姓名
*/
private String name;
/**
* 所患病症(对应字符串类型) 英文逗号 分割
*/
private String diseaseIds;
/**
* 患者标签(对应数字类型) / 分割
*/
private String tagIds;
@RelationOneToMany(
selfField = "diseaseIds",
splitBy = ",", //使用 , 进行分割
targetTable = "tb_disease", //只获取某个字段值需要填入目标表名
targetField = "diseaseId", //测试目标字段是字符串类型是否正常转换
valueField = "name" //测试只获取某个字段值是否正常
)
private List<String> diseaseNameList;
@RelationOneToMany(
selfField = "tagIds",
splitBy = "/", //使用 / 进行分割
targetField = "tagId" //测试目标字段是数字类型是否正常转换
)
private List<Tag> tagList;
@RelationOneToMany(
selfField = "diseaseIds",
splitBy = ",", //使用 , 进行分割
targetField = "diseaseId", //测试目标字段是字符串类型是否正常转换
mapKeyField = "diseaseId" //测试Map映射
)
private Map<String, Disease> diseaseMap;
public Integer getPatientId() {
return patientId;
}
public void setPatientId(Integer patientId) {
this.patientId = patientId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDiseaseIds() {
return diseaseIds;
}
public void setDiseaseIds(String diseaseIds) {
this.diseaseIds = diseaseIds;
}
public String getTagIds() {
return tagIds;
}
public void setTagIds(String tagIds) {
this.tagIds = tagIds;
}
public List<String> getDiseaseNameList() {
return diseaseNameList;
}
public void setDiseaseNameList(List<String> diseaseNameList) {
this.diseaseNameList = diseaseNameList;
}
public List<Tag> getTagList() {
return tagList;
}
public void setTagList(List<Tag> tagList) {
this.tagList = tagList;
}
public Map<String, Disease> getDiseaseMap() {
return diseaseMap;
}
public void setDiseaseMap(Map<String, Disease> diseaseMap) {
this.diseaseMap = diseaseMap;
}
}

View File

@ -0,0 +1,44 @@
package com.mybatisflex.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
/**
* 标签
*
* @author Ice 2023/09/26
* @version 1.0
*/
@Table(value = "tb_tag")
public class Tag implements Serializable {
private static final long serialVersionUID = 5600670055904157386L;
/**
* ID
*/
@Id
private Integer tagId;
/**
* 标签名称
*/
private String name;
public Integer getTagId() {
return tagId;
}
public void setTagId(Integer tagId) {
this.tagId = tagId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,59 @@
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for tb_disease
-- ----------------------------
DROP TABLE IF EXISTS `tb_disease`;
CREATE TABLE `tb_disease` (
`disease_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'ID',
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '疾病名称',
PRIMARY KEY (`disease_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '疾病信息' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of tb_disease
-- ----------------------------
INSERT INTO `tb_disease` VALUES ('1', '心脑血管疾病');
INSERT INTO `tb_disease` VALUES ('2', '消化系统疾病');
INSERT INTO `tb_disease` VALUES ('3', '神经系统疾病');
INSERT INTO `tb_disease` VALUES ('4', '免疫系统疾病');
-- ----------------------------
-- Table structure for tb_patient
-- ----------------------------
DROP TABLE IF EXISTS `tb_patient`;
CREATE TABLE `tb_patient` (
`patient_id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姓名',
`disease_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所患病症(对应字符串类型) 英文逗号 分割',
`tag_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '患者标签(对应数字类型) / 分割',
PRIMARY KEY (`patient_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '患者信息' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of tb_patient
-- ----------------------------
INSERT INTO `tb_patient` VALUES (1, '张三', '1', NULL);
INSERT INTO `tb_patient` VALUES (2, '李四', '1,2', '1');
INSERT INTO `tb_patient` VALUES (3, '王五', '1,2,3', '1/2');
INSERT INTO `tb_patient` VALUES (4, '赵六', '1,2,3,4', '1/2/3');
-- ----------------------------
-- Table structure for tb_tag
-- ----------------------------
DROP TABLE IF EXISTS `tb_tag`;
CREATE TABLE `tb_tag` (
`tag_id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '标签名',
PRIMARY KEY (`tag_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '标签' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of tb_tag
-- ----------------------------
INSERT INTO `tb_tag` VALUES (1, 'VIP');
INSERT INTO `tb_tag` VALUES (2, 'JAVA开发');
INSERT INTO `tb_tag` VALUES (3, 'Web开发');
SET FOREIGN_KEY_CHECKS = 1;

View File

@ -0,0 +1,30 @@
package com.mybatisflex.test.mapper;
import com.alibaba.fastjson2.JSON;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.test.model.PatientVO1;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
/**
* 患者相关测试
*
* @author Ice 2023/09/26
* @version 1.0
*/
@SpringBootTest
@SuppressWarnings("all")
public class PatientMapperTest {
@Autowired
private PatientMapper patientMapper;
@Test
public void testRelationOneToManySplitBy() {
PatientVO1 patientVO1 = patientMapper.selectOneWithRelationsByQueryAs(QueryWrapper.create().orderBy(PatientVO1::getPatientId, false).limit(1), PatientVO1.class);
System.out.println(JSON.toJSONString(patientVO1));
}
}