MybatisPlus实现高效的多对多查询
1、前置
事先声明一下代码中蕴含了大量的Stream和Lambda表达式操作,还不清楚的小伙伴可以去参考一下Java8新特性Stream流,而却我是用的是MybatisPlus这方面不清楚的也可以参考一下MybatisPlus基础用法;中间的对象转换除了使用Spring的BeanProperties外还使用了Mapstruct,关于MapStruct可以参考MapStruct使用
2、测试前准备
创建几张表用于做演示
DROP TABLE IF EXISTS `tb_dept`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_dept` (
`dept_id` bigint(20) NOT NULL COMMENT '主键ID(全局唯一)',
`dept_name` varchar(30) DEFAULT NULL COMMENT '部门名称',
`staff` int(11) DEFAULT NULL COMMENT '员工',
`tel` varchar(50) DEFAULT NULL COMMENT '联系电话',
`deleted` bit(1) DEFAULT b'0' COMMENT '逻辑删除(0:未删除;1:已删除)',
`version` int(11) DEFAULT '0' COMMENT '乐观锁',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`dept_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='部门';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `tb_dept`
--
LOCK TABLES `tb_dept` WRITE;
/*!40000 ALTER TABLE `tb_dept` DISABLE KEYS */;
INSERT INTO `tb_dept` (`dept_id`, `dept_name`, `staff`, `tel`, `deleted`, `version`, `gmt_create`, `gmt_modified`) VALUES (10,'1665646580778',20,'88886666',_binary '\0',4,'2020-10-30 11:48:19','2022-10-13 15:36:20'),(11,'Mysql',12,'80802121',_binary '\0',0,'2020-10-30 11:48:44','2021-05-24 15:11:20'),(12,'Tomcat',12,'23231212',_binary '\0',0,'2020-10-30 11:48:44','2021-05-24 15:11:23'),(13,'Nginx',13,'7116201',_binary '\0',0,'2020-10-30 11:48:45','2021-05-24 15:11:26');
/*!40000 ALTER TABLE `tb_dept` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `tb_stu_sub_relation`
--
DROP TABLE IF EXISTS `tb_stu_sub_relation`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_stu_sub_relation` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`stu_id` int(11) DEFAULT NULL COMMENT '学号ID',
`sub_id` int(11) DEFAULT NULL COMMENT '学生ID',
`score` int(11) DEFAULT NULL COMMENT '分数',
PRIMARY KEY (`id`),
KEY `stu_id` (`stu_id`),
KEY `sub_id` (`sub_id`),
CONSTRAINT `tb_stu_sub_relation_ibfk_1` FOREIGN KEY (`stu_id`) REFERENCES `tb_student` (`stu_id`),
CONSTRAINT `tb_stu_sub_relation_ibfk_2` FOREIGN KEY (`sub_id`) REFERENCES `tb_subject` (`sub_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='学生与课程关系表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `tb_stu_sub_relation`
--
LOCK TABLES `tb_stu_sub_relation` WRITE;
/*!40000 ALTER TABLE `tb_stu_sub_relation` DISABLE KEYS */;
INSERT INTO `tb_stu_sub_relation` (`id`, `stu_id`, `sub_id`, `score`) VALUES (1,1,1,88),(2,1,2,67),(3,2,1,82);
/*!40000 ALTER TABLE `tb_stu_sub_relation` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `tb_student`
--
DROP TABLE IF EXISTS `tb_student`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_student` (
`stu_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '学号ID',
`stu_name` varchar(30) DEFAULT NULL COMMENT '姓名',
PRIMARY KEY (`stu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='学生表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `tb_student`
--
LOCK TABLES `tb_student` WRITE;
/*!40000 ALTER TABLE `tb_student` DISABLE KEYS */;
INSERT INTO `tb_student` (`stu_id`, `stu_name`) VALUES (1,'张三'),(2,'李四'),(3,'王五');
/*!40000 ALTER TABLE `tb_student` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `tb_subject`
--
DROP TABLE IF EXISTS `tb_subject`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_subject` (
`sub_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '课程ID',
`sub_name` varchar(30) DEFAULT NULL COMMENT '课程名',
PRIMARY KEY (`sub_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='课程表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `tb_subject`
--
LOCK TABLES `tb_subject` WRITE;
/*!40000 ALTER TABLE `tb_subject` DISABLE KEYS */;
INSERT INTO `tb_subject` (`sub_id`, `sub_name`) VALUES (1,'英语'),(2,'数学'),(3,'计算机'),(4,'操作系统'),(5,'数据库');
/*!40000 ALTER TABLE `tb_subject` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `tb_user`
--
DROP TABLE IF EXISTS `tb_user`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_user` (
`user_id` bigint(20) NOT NULL COMMENT '主键ID(全局唯一)',
`user_name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
`dept_id` bigint(20) DEFAULT NULL COMMENT '部门ID',
`deleted` bit(1) DEFAULT b'0' COMMENT '逻辑删除(0:未删除;1:已删除)',
`version` int(11) DEFAULT '0' COMMENT '乐观锁',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`user_id`),
KEY `dept_id` (`dept_id`),
CONSTRAINT `tb_user_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `tb_dept` (`dept_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='书籍';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `tb_user`
--
LOCK TABLES `tb_user` WRITE;
/*!40000 ALTER TABLE `tb_user` DISABLE KEYS */;
INSERT INTO `tb_user` (`user_id`, `user_name`, `age`, `email`, `dept_id`, `deleted`, `version`, `gmt_create`, `gmt_modified`) VALUES (1,'1665646693248',1,'ab@c.c',10,_binary '\0',0,NULL,'2022-10-13 15:38:13'),(2,'Jack',3,'test2@baomidou.com',11,_binary '\0',0,NULL,'2021-05-24 15:12:04'),(3,'Billie',2,'test5@baomidou.com',12,_binary '\0',0,NULL,'2021-10-21 10:51:24'),(4,'didi',12,'test@qq.com',12,_binary '\0',0,'2021-06-05 19:22:46','2021-10-21 14:38:26');
/*!40000 ALTER TABLE `tb_user` ENABLE KEYS */;
UNLOCK TABLES;
3、我的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qbb</groupId>
<artifactId>MybatisPlusDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>2.7.3</version>
<relativePath/>
</parent>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<!--swagger-ui-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.3.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.3.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
</project>
4、单表查询
单表查询MybaitsPlus已经做的很好了,我就不重复了
@Operation(summary = "单表查询-----用户列表")
@GetMapping("/list")
public Q list(User user) {
return Q.success(userService.list(Wrappers.query(user)));
}
@Operation(summary = "单表查询-----用户列表page")
@GetMapping("/page")
public Q page(PageEntity pageEntity, User user) {
return Q.success(userService.page(pageEntity.toPage(), Wrappers.lambdaQuery(user)));
}
@Operation(summary = "单表查询-----新增")
@PostMapping("/add")
public Q add(@RequestBody User user) {
return Q.success(userService.save(user));
}
@Operation(summary = "单表查询-----修改")
@PutMapping("/edit")
public Q edit(@RequestBody User user) {
return Q.success(userService.updateById(user));
}
@Operation(summary = "单表查询-----批量删除")
@DeleteMapping("/batchRemove")
public Q batchRemove(@Parameter(name = "ids", description = "用户ID列表") @RequestBody Long[] ids) {
return Q.success(userService.removeBatchByIds(Arrays.asList(ids)));
}
@Operation(summary = "单表查询-----根据ID查询")
@GetMapping("/detail/{id}")
public Q detail(@Parameter(name = "id", description = "用户ID") @PathVariable("id") Long id) {
return Q.success(userService.getById(id));
}
5、一对一查询
/*===========================一对一查询START===============================*/
@Override
public UserVO voDetail(Long id) {
// 查询用户信息
User user = this.getById(id);
// 转换为vo对象
UserVO userVO = Optional.ofNullable(user).map(UserVO::new).orElse(null);
// 组装数据
Optional.ofNullable(userVO).ifPresent(this::addDeptNameInfo);
return userVO;
}
private void addDeptNameInfo(UserVO userVO) {
Dept dept = deptService.getOne(Wrappers.<Dept>lambdaQuery().eq(Dept::getDeptId, userVO.getDeptId()));
Optional.ofNullable(dept).ifPresent(d -> userVO.setDeptName(d.getDeptName()));
}
@Override
public IPage<UserVO> voPage(PageEntity page, User user) {
// 先根据条件查询用户列表
IPage<User> userPage = this.page(page.toPage(), Wrappers.lambdaQuery(user));
// 初始化Vo
IPage<UserVO> userVoPage = userPage.convert(UserVO::new);
if (userVoPage.getRecords().size() > 0) {
addDeptNameInfo(userVoPage);
}
return userVoPage;
}
private void addDeptNameInfo(IPage<UserVO> userVoPage) {
// 提取用户userId,方便批量查询
Set<Long> deptIds = userVoPage.getRecords().stream().map(User::getDeptId).collect(toSet());
// 根据deptId查询deptName
List<Dept> dept = deptService.list(Wrappers.lambdaQuery(Dept.class).in(Dept::getDeptId, deptIds));
// 构造映射关系,方便匹配deptId与deptName
Map<Long, String> hashMap = dept.stream().collect(toMap(Dept::getDeptId, Dept::getDeptName));
// 将查询补充的信息添加到Vo中
userVoPage.convert(e -> {
e.setDeptName(hashMap.get(e.getDeptId()));
return e;
});
}
@Override
public List<UserVO> voList(User user) {
List<User> userList = this.list(Wrappers.lambdaQuery(user));
List<UserVO> userVOList = userList.stream().map(UserVO::new).collect(Collectors.toList());
// 此步骤可以有多个
addDeptNameInfo(userVOList);
return userVOList;
}
private void addDeptNameInfo(List<UserVO> userVOList) {
// 提取userVOList中的deptId集合
Set<Long> deptIds = userVOList.stream().map(UserVO::getDeptId).collect(toSet());
// 根据in(id1,id2,id3...)查询
List<Dept> depts = deptService.list(Wrappers.<Dept>lambdaQuery().select(Dept::getDeptId, Dept::getDeptName).in(Dept::getDeptId, deptIds));
// 构造映射关系,方便匹配deptId与deptName
Map<Long, String> hashMap = depts.stream().collect(toMap(Dept::getDeptId, Dept::getDeptName));
// 封装Vo,并添加到集合中(关键内容)
userVOList.forEach(e -> e.setDeptName(hashMap.get(e.getDeptId())));
}
// ===================================== easy写法 =========================================
@Override
public UserVO voDetailEasy(Long id) {
UserVO userVO = EntityUtils.toObj(this.getById(id), UserVO::new);
Dept dept = deptService.getById(userVO.getDeptId());
return CONVERT.appendAttrToUserVO(dept, userVO);
}
@Override
public IPage<UserVO> voPageEasy(PageEntity page, User user) {
IPage<UserVO> toPage = EntityUtils.toPage(page(page.toPage(User.class), Wrappers.lambdaQuery(user)), UserVO::new);
Set<Long> deptIds = EntityUtils.toSet(toPage.getRecords(), UserVO::getDeptId);
Map<Long, Dept> deptMap = EntityUtils.toMap(deptService.listByIds(deptIds), Dept::getDeptId, e -> e);
toPage.convert(e -> CONVERT.appendAttrToUserVO(deptMap.get(e.getDeptId()), e));
return toPage;
}
@Override
public List<UserVO> voListEasy(User user) {
List<UserVO> userVOList = EntityUtils.toList(list(Wrappers.lambdaQuery(user)), UserVO::new);
Set<Long> deptIds = EntityUtils.toSet(userVOList, UserVO::getDeptId);
Map<Long, Dept> deptMap = EntityUtils.toMap(deptService.listByIds(deptIds), Dept::getDeptId, e -> e);
userVOList = userVOList.parallelStream().map(e -> CONVERT.appendAttrToUserVO(deptMap.get(e.getDeptId()), e)).collect(Collectors.toList());
return userVOList;
}
/*===========================一对一查询END===============================*/
6、一对多查询
/**
* 单个对象:一个部门对应多个用户
*
* @param id
* @return
*/
@Override
public DeptVO voDetailEasyOneToMany(Long id) {
// 先查询部门信息
Dept dept = this.getById(id);
// 把部门信息转换成deptVO
DeptVO deptVO = Optional.ofNullable(dept).map(CONVERT::deptToDeptVO).orElse(null);
// 填充部门的员工信息
Optional.ofNullable(deptVO).ifPresent(this::addUserInfo);
return deptVO;
}
private void addUserInfo(DeptVO deptVO) {
// 根据部门ID查询用户信息
List<User> userList = userService.list(Wrappers.lambdaQuery(User.class).eq(User::getDeptId, deptVO.getDeptId()));
Optional.ofNullable(userList).ifPresent(deptVO::setUserList);
}
/**
* 分页查询:一个部门对应多个用户
*
* @param page
* @param dept
* @return
*/
@Override
public IPage<DeptVO> voPageEasyOneToMany(PageEntity page, Dept dept) {
IPage<DeptVO> toPage = EntityUtils.toPage(page(page.toPage(Dept.class), Wrappers.lambdaQuery(dept)), DeptVO::new);
if (toPage.getRecords().size() > 0) {
addUserInfo(toPage);
}
return toPage;
}
private void addUserInfo(IPage<DeptVO> toPage) {
// 查询部门对应的多个员工
Set<Long> deptIds = EntityUtils.toSet(toPage.getRecords(), DeptVO::getDeptId);
// 用批量deptId查询用户信息
List<User> userList = userService.list(Wrappers.lambdaQuery(User.class).in(User::getDeptId, deptIds));
// 使用stream流对用户信息进行分组 Map<deptId,用户列表>,方便后面根据deptId直接获取用户列表信息
Map<Long, List<User>> listMap = userList.parallelStream().collect(Collectors.groupingBy(User::getDeptId));
// 方式一:
// toPage.getRecords().forEach(e -> e.setUserList(listMap.get(e.getDeptId())));
// 方式二:
toPage.convert(deptVO -> {
deptVO.setUserList(listMap.get(deptVO.getDeptId()));
return deptVO;
});
}
/**
* 列表查询:一个部门对应多个用户
*
* @param dept
* @return
*/
@Override
public List<DeptVO> voListEasyOneToMany(Dept dept) {
// 查询出部门列表
List<DeptVO> toList = EntityUtils.toList(list(Wrappers.lambdaQuery(dept)), DeptVO::new);
Set<Long> deptIds = EntityUtils.toSet(toList, DeptVO::getDeptId);
List<User> userList = userService.list(Wrappers.lambdaQuery(User.class).in(User::getDeptId, deptIds));
Map<Long, List<User>> listMap = userList.parallelStream().collect(Collectors.groupingBy(User::getDeptId));
toList.forEach(e -> e.setUserList(listMap.get(e.getDeptId())));
return toList;
}
7、多对多查询
// =======================================================根据学生信息查询对应课程信息 START=======================================================
/**
* 根据学生ID查询学生信息,并且查询此学生的课程信息
*
* @param id
* @return
*/
@Override
public StudentVO voDetailEasyStuManyToSubMany(Long id) {
// 先查询学生信息
Student student = studentService.getById(id);
// 把学生信息转换成学生BO
StudentVO studentVO = EntityUtils.toObj(student, StudentVO::new);
// 查询匹配的关系
List<StuSubRelation> stuSubRelationList = this.list(Wrappers.<StuSubRelation>lambdaQuery().eq(StuSubRelation::getStuId, id));
// 获取课程ID列表
Set<Long> subIds = EntityUtils.toSet(stuSubRelationList, StuSubRelation::getSubId);
if (Objects.nonNull(studentVO) && !subIds.isEmpty()) {
// 根据课程ID列表查询课程信息
List<Subject> subjectList = subjectService.list(Wrappers.<Subject>lambdaQuery().in(Subject::getSubId, subIds));
// domain ---> BO
List<SubjectBO> subjectBOList = SubjectConvert.CONVERT.subListToSubBOList(subjectList);
// 转换为table对象 table对象可以理解为是一个双键Map ===> Map<rowKey,Map<columnKey,value>>
// Table<Long, Long, StuSubRelation> table = TableUtils.createHashTable(stuSubRelationList, StuSubRelation::getStuId, StuSubRelation::getSubId);
subjectBOList.forEach(StuSubRelationConvert.CONVERT::stuSubRelationToSubjectBO);
studentVO.setSubjectBOList(subjectBOList);
}
return studentVO;
}
/**
* 根据查询条件查询学生信息列表,并且查询出对应学生的课程信息
*
* @param student 查询条件
* @return
*/
@Override
public List<StudentVO> voListEasyStuManyToSubMany(Student student) {
// 根据条件查询学生信息列表
List<Student> studentList = studentService.list(Wrappers.lambdaQuery(student));
// student ---> studentVO
List<StudentVO> studentVOList = EntityUtils.toList(studentList, StudentVO::new);
// 提取studentIds
Set<Long> studentIds = EntityUtils.toSet(studentVOList, Student::getStuId);
if (studentIds.size() == 0) {
return studentVOList;
}
// 根据studentIds去中间表中查询对应关系列表
List<StuSubRelation> stuSubRelations = list(Wrappers.<StuSubRelation>lambdaQuery().in(StuSubRelation::getStuId, studentIds));
// 提取subjectIds
Set<Long> subjectIds = EntityUtils.toSet(stuSubRelations, StuSubRelation::getSubId);
if (subjectIds.size() == 0) {
return studentVOList;
}
/**
* 分组转换:
* 源数据:
* 1 - 1
* 1 - 2
* 2 - 1
* 2 - 3
* 转换后:
* 1 - [1,2]
* 2 - [1,3]
*/
Map<Long, List<Long>> map = stuSubRelations.stream().collect(Collectors.groupingBy(StuSubRelation::getStuId,
Collectors.mapping(StuSubRelation::getSubId, Collectors.toList())));
// 转换为table对象 table对象可以理解为是一个双键Map ===> Map<rowKey,Map<columnKey,value>> 详细的使用参考:https://www.cnblogs.com/qbbit/p/16965597.html
// Table<Long, Long, StuSubRelation> table = TableUtils.createHashTable(stuSubRelations, StuSubRelation::getStuId, StuSubRelation::getSubId);
// 根据subjectIds查询课程信息列表
List<Subject> subjectList = subjectService.list(Wrappers.<Subject>lambdaQuery().in(Subject::getSubId, subjectIds));
// 使用MapStruct进行高效数据转换
List<SubjectBO> subjectBOList = SubjectConvert.CONVERT.subListToSubBOList(subjectList);
// 设置课程信息
studentVOList.forEach(studentAction(map, subjectBOList));
return studentVOList;
}
/**
* 根据查询条件查询学生信息分页列表,并且查询出对应学生的课程信息
*
* @param page 分页信息
* @param student 查询条件
* @return
*/
@Override
public IPage<StudentVO> voPageEasyStuManyToSubMany(IPage<Student> page, Student student) {
IPage<Student> studentIPage = studentService.page(page, Wrappers.lambdaQuery(student));
IPage<StudentVO> studentVOPage = EntityUtils.toPage(studentIPage, StudentVO::new);
Set<Long> studentIds = EntityUtils.toSet(studentVOPage.getRecords(), Student::getStuId);
if (studentIds.size() == 0) {
return studentVOPage;
}
List<StuSubRelation> stuSubRelations = list(Wrappers.lambdaQuery(StuSubRelation.class).in(StuSubRelation::getStuId, studentIds));
Set<Long> subjectIds = EntityUtils.toSet(stuSubRelations, StuSubRelation::getSubId);
if (subjectIds.size() == 0) {
return studentVOPage;
}
Map<Long, List<Long>> map = stuSubRelations.stream().collect(Collectors.groupingBy(StuSubRelation::getStuId, Collectors.mapping(StuSubRelation::getSubId, Collectors.toList())));
List<Subject> subjectList = subjectService.list(Wrappers.lambdaQuery(Subject.class).in(Subject::getSubId, subjectIds));
List<SubjectBO> subjectBOList = SubjectConvert.CONVERT.subListToSubBOList(subjectList);
studentVOPage.getRecords().forEach(studentAction(map, subjectBOList));
return studentVOPage;
}
@NotNull
private static Consumer<StudentVO> studentAction(Map<Long, List<Long>> map, List<SubjectBO> subjectBOList) {
return studentVO -> {
List<SubjectBO> list = subjectBOList.stream().filter(e -> map.get(studentVO.getStuId()) != null && map.get(studentVO.getStuId()).contains(e.getSubId())).collect(Collectors.toList());
list.forEach(StuSubRelationConvert.CONVERT::stuSubRelationToSubjectBO);
studentVO.setSubjectBOList(list);
};
}
// =======================================================根据学生信息查询对应课程信息 END=======================================================
// =======================================================根据课程信息查询对应学生信息 START=======================================================
/**
* 根据课程ID查询课程信息,并且查询此课程的学生信息
*
* @param id 课程ID
* @return 一条记录
*/
@Override
public SubjectVO voDetailEasySubManyToStuMany(Long id) {
// 根据课程ID查询课程信息
Subject subject = subjectService.getById(id);
// 将subject转换为subjectVO
SubjectVO subjectVO = EntityUtils.toObj(subject, SubjectVO::new);
// 查询匹配关系
List<StuSubRelation> stuSubRelationList = this.list(Wrappers.<StuSubRelation>lambdaQuery().eq(StuSubRelation::getSubId, id));
// 获取学生ID列表
Set<Long> stuIds = EntityUtils.toSet(stuSubRelationList, StuSubRelation::getStuId);
if (Objects.nonNull(subjectVO) && stuIds.size() > 0) {
// 根据学生ID列表查询学生信息
List<Student> studentList = studentService.list(Wrappers.<Student>lambdaQuery().in(Student::getStuId, stuIds));
// domain ---> BO
List<StudentBO> studentBOList = StudentConvert.CONVERT.stuListToStuBOList(studentList);
studentBOList.forEach(StuSubRelationConvert.CONVERT::stuSubRelationToStudentBO);
subjectVO.setStudentBOList(studentBOList);
}
return subjectVO;
}
/**
* 根据查询条件查询学生信息列表,并且查询出对应学生的课程信息
*
* @param subject 查询条件
* @return
*/
@Override
public List<SubjectVO> voListEasySubManyToStuMany(Subject subject) {
// 根据条件查询课程列表
List<Subject> subjectList = subjectService.list(Wrappers.lambdaQuery(subject));
// subject ---> subjectVO
List<SubjectVO> subjectVOList = EntityUtils.toList(subjectList, SubjectVO::new);
// 提取subjectIds
Set<Long> subjectIds = EntityUtils.toSet(subjectVOList, Subject::getSubId);
if (subjectIds.size() == 0) {
return subjectVOList;
}
// 提取subjectIds去中间表查询对应关系列表
List<StuSubRelation> stuSubRelationList = list(Wrappers.<StuSubRelation>lambdaQuery().in(StuSubRelation::getSubId, subjectIds));
// 提取studentIds
Set<Long> studentIds = EntityUtils.toSet(stuSubRelationList, StuSubRelation::getStuId);
if (studentIds.size() == 0) {
return subjectVOList;
}
Map<Long, List<Long>> map = stuSubRelationList.stream()
.collect(Collectors.groupingBy(StuSubRelation::getStuId, Collectors.mapping(StuSubRelation::getSubId, Collectors.toList())));
List<Student> studentList = studentService.list(Wrappers.<Student>lambdaQuery().in(Student::getStuId, studentIds));
List<StudentBO> studentBOList = StudentConvert.CONVERT.stuListToStuBOList(studentList);
subjectVOList.forEach(subjectAction(map, studentBOList));
return subjectVOList;
}
/**
* 根据查询条件查询学生信息分页列表,并且查询出对应学生的课程信息
*
* @param page 分页信息
* @param subject 查询条件
* @return
*/
@Override
public IPage<SubjectVO> voPageEasySubManyToStuMany(Page<Subject> page, Subject subject) {
IPage<SubjectVO> subjectVOPage = EntityUtils.toPage(subjectService.page(page, Wrappers.lambdaQuery(subject)), SubjectVO::new);
Set<Long> subjectIds = EntityUtils.toSet(subjectVOPage.getRecords(), Subject::getSubId);
if (subjectIds.size() == 0) {
return subjectVOPage;
}
List<StuSubRelation> stuSubRelations = list(Wrappers.lambdaQuery(StuSubRelation.class).in(StuSubRelation::getSubId, subjectIds));
Set<Long> studentIds = EntityUtils.toSet(stuSubRelations, StuSubRelation::getStuId);
if (studentIds.size() == 0) {
return subjectVOPage;
}
Map<Long, List<Long>> map = stuSubRelations.stream()
.collect(Collectors.groupingBy(StuSubRelation::getSubId, Collectors.mapping(StuSubRelation::getStuId, Collectors.toList())));
List<Student> studentList = studentService.list(Wrappers.lambdaQuery(Student.class).in(Student::getStuId, studentIds));
List<StudentBO> studentBOList = StudentConvert.CONVERT.stuListToStuBOList(studentList);
subjectVOPage.getRecords().forEach(subjectAction(map, studentBOList));
return subjectVOPage;
}
@NotNull
private static Consumer<SubjectVO> subjectAction(Map<Long, List<Long>> map, List<StudentBO> studentBOList) {
return (subjectVO) -> {
List<StudentBO> list = studentBOList.stream()
.filter(e -> map.get(subjectVO.getSubId()) != null && map.get(subjectVO.getSubId()).contains(e.getStuId())).collect(Collectors.toList());
list.forEach(StuSubRelationConvert.CONVERT::stuSubRelationToStudentBO);
subjectVO.setStudentBOList(list);
};
}
// =======================================================根据学生信息查询对应课程信息 END=======================================================
代码仓库
MybatisPlus实现高效的多对多查询的更多相关文章
- 22Mybatis_订单商品数据模型_多对多查询以及对多对多查询的总结
之前讲了一对一,一对多查询,这篇文章讲的是多对多. 先给出需求:查询用户及用户购买商品信息. 我们由之前的文章知道,这个需求是多对多的. 还是那个终止我们的mybatis所做的不管是之前的一对一还是一 ...
- mybatis(一、原理,一对多,多对一查询)
MyBatis框架及原理分析 MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架,其主要就完成2件事情: 封装JDBC操作 利用反射打通Java类与SQL语句之间的相互转换 ...
- flask的orm框架(SQLAlchemy)-一对多查询以及多对多查询
一对多,多对多是什么? 一对多.例如,班级与学生,一个班级对应多个学生,或者多个学生对应一个班级. 多对多.例如,学生与课程,可以有多个学生修同一门课,同时,一门课也有很多学生. 一对多查询 如果一个 ...
- SpringBoot使用Mybatis注解进行一对多和多对多查询(2)
SpringBoot使用Mybatis注解进行一对多和多对多查询 GitHub的完整示例项目地址kingboy-springboot-data 一.模拟的业务查询 系统中的用户user都有唯一对应的地 ...
- MyBatis多对多查询
-------------------siwuxie095 MyBatis 多对多查询 以订单和商品为例,即 一个订单可 ...
- mybatis由浅入深day02_4多对多查询_多对多查询总结
4 多对多查询 4.1 需求(查询用户及用户购买商品信息) 查询用户及用户购买商品信息. 4.2 sql语句 查询主表是:用户表 关联表:由于用户和商品没有直接关联,通过订单和订单明细进行关联,所以关 ...
- 基于对象的跨表查询,多对多查询,多对多操作,聚合查询和分组查询,F查询和Q 查询
基于对象的跨表查询 一对多查询(班级表和学生表) 表结构创建 class Class(models.Model): id = models.AutoField(primary_key=True) cn ...
- mybatis学习记录六——一对一、一对多和多对多查询
9 订单商品数据模型 9.1 数据模型分析思路 1.每张表记录的数据内容 分模块对每张表记录的内容进行熟悉,相当 于你学习系统 需求(功能)的过程. 2.每张表重要的字段设置 非空 ...
- 数据库开发-Django ORM的多对多查询
数据库开发-Django ORM的多对多查询 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.联合主键问题 CREATE TABLE `employees` ( `emp_no` ...
- day03-Mybatis中一对一、一对多、多对多查询
一对一查询 一对一的表结构: my_account表: my_user表: 一对一是互相的,A可以找到B,B也可以找到A,方法是一样的,这里就只写一个方向的 通过my_count表找到my_user表 ...
随机推荐
- React Native实现Toast轻提示和loading
React Native 封装Toast 前言 使用react native的小伙伴都知道,官方并未提供轻提示组件,只提供了ToastAndroid API,顾名思义,只能再安卓环境下使用,对于ios ...
- 手机用户的开源福音「GitHub 热点速览」
不知道多少用安卓机的小伙伴,被开屏广告烦过.相比有些克制的 iOS 机,安卓机是个应用基本上都有开屏广告,少则 3s 多则 10s,本周获得 1k+ star 的 Android-Touch-Help ...
- HTML一键打包APK工具最新版1.9.1更新(附下载地址)
HMTL网址打包APK,可以把本地HTML项目, Egret游戏,网页游戏,或者网站打包为一个安卓应用APK文件,无需编写任何代码,也无需配置安卓开发环境,支持在最新的安卓设备上安装运行. HTML一 ...
- Github、Gitee优秀的开源项目
收集 Github.Gitee优秀的开源项目,并进行归类整理.项目地址 目录 编程语言项目 SprinBoot 项目 源码分析项目 前后端分离项目 Vue2 项目 Vue3 项目 微服务项目 Api ...
- 「luogu - P3158」「cqoi 2011」放棋子
link. 解读一下,大概就是一种颜色放进去就会占据一行一列,dp 状态就好想了:\(f_{i,j,k}\) 表示恰好用完前 \(k\) 种颜色的所有棋子,占据了 \(i\) 行 \(j\) 列的方案 ...
- destoon关于archiver归档的性能优化
今天在处理一个项目时候发现archiver单个模块归档超过百万数据,打开速度就特慢,所以打开archiver下index.php文件进行分析,发现有句sql作怪 1 $result = $db-> ...
- Python并发编程——IO模型、阻塞IO、非阻塞IO、多路复用、异步IO、IO模型比较、selectors模块、复习网络和并发知识点
文章目录 每日测验 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 异步IO(Asy ...
- pta2023年9月7日 第五期
5月23日 11月14日 有效期3年: 更新方式待定: 双方认证合作CCF编程培训师资认证(PTA)中国计算机学会https://pta.ccf.org.cn/中国科教工作者协会(原:中国青 ...
- Java21上手体验-分代ZGC和虚拟线程
一.导语 几天前Oracle刚刚发布了Java21, 由于这是最新的LTS版本,引起了大家的关注. 我也第一时间在个人项目中进行了升级体验. 一探究竟,和大家分享. 二.Java21更新内容介绍 官方 ...
- 手动添加winform的combobox和listbox名称和值
先定义一个ListItem类,工程内其他窗体都可以用的. public class ListItem : Object { public string Text { get; ...