MyBatis

Mybatis上手教程–select语句使用collection查询一对多关联关系场景

一 一对多关联场景

通常,一个部门包含多个员工信息,一个论坛包含多个帖子等等场景。那么,现在如果想要查询一个部门信息,以及该部门下包含的所有员工信息。该怎么处理呢?我们前面都是处理的一对一的关联关系。

二 一对多关联查询示例流程

1 部门表实体类添加员工字段List<Employee>
package com.knockatdatabase;

import java.util.List;

/**
* @Author:asher
* @Date:2021/10/10 11:16
* @Description:com.knockatdatabase
* @Version:1.0
*/
public class Department {
   private int id;
   private String deptName;
   private List<Employee> employeeList;

   public List<Employee> getEmployeeList() {
       return employeeList;
  }

   public void setEmployeeList(List<Employee> employeeList) {
       this.employeeList = employeeList;
  }
...
}    

给实体类Department 添加1个属性,数据类型是List带有Employee泛型;然后添加getter/setter。

2 DepartmentMapper.java接口文件添加新的方法
    Department getDepartmentByIdWithEmployees(Integer id);
3 DepartmentMapper.xml文件添加SQL语句
<?xml version="1.0" encoding="UTF-8" ?>
       <!DOCTYPE mapper
               PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
               "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.knockatdatabase.dao.DepartmentMapper">
       <select id="getDepartmentById" resultType="com.knockatdatabase.Department">
               select id,dept_name as deptName from tbl_dept where id=#{id}
      </select>

<resultMap id="oneDeptWithMoreEmps" type="com.knockatdatabase.Department">
       <id column="did" property="id"></id>
       <result column="dept_name" property="deptName"></result>
       <collection property="employeeList" ofType="com.knockatdatabase.Employee">
               <id column="id" property="id"></id>
               <result column="last_name" property="lastName"></result>
               <result column="email" property="mail"></result>
               <result column="gender" property="gender"></result>
      </collection>
</resultMap>
       <select id="getDepartmentByIdWithEmployees" resultMap="oneDeptWithMoreEmps">
       select dept.id did,dept.dept_name,emp.id id,emp.last_name,emp.email,emp.gender gender
       from tbl_dept dept left join tbl_employee emp
       on dept.id = emp.did
       where dept.id = #{id}
      </select>
</mapper>

其中,新定义1个resultMap,type写Department实体类全类名,表示返回的是Department实体类。然后依次写主键字段用id,普通字段用result标签。

接下来,新起1个collection标签,property写Department实体类中的属性名,employeeList,此处的名字要严格一致。ofType,表示的是集合里的存放的对象的类型,该属性值对应哪个具体的实体类。然后,再在collection标签页中依次填Employee实体类和数据库表中的字段映射关系。

最后,写一个关联查询的SQL,注意的是,字段列表中,并没有写部门表里关于员工的字段值,因为数据库表中,也确实没有该字段。这里,只不过是我们人为的在Java bean的实体类Department上虚拟出来的一个属性字段:List<Employee>,然后紧接着就是写员工表里的字段列表。

4 Java测试代码
    @Test
   public void testOneDeptWithMoreEmps() {
       String resource = "mybatis-config.xml";
       SqlSession sqlSession = null;
       try{
           InputStream inputStream = Resources.getResourceAsStream(resource);
           SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
           sqlSession = sqlSessionFactory.openSession();
           DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
           Department departmentByIdWithEmployees = mapper.getDepartmentByIdWithEmployees(1);
           System.out.println(departmentByIdWithEmployees);
           System.out.println(departmentByIdWithEmployees.getEmployeeList());
      } catch (IOException e) {
           e.printStackTrace();
      }finally {
           sqlSession.close();
      }
  }
//结果:
DEBUG [main] - Created connection 825658265.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - ==>  Preparing: select dept.id did,dept.dept_name,emp.id id,emp.last_name,emp.email,emp.gender gender from tbl_dept dept left join tbl_employee emp on dept.id = emp.did where dept.id = ?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 2
Department{id=1, deptName='市场部', employeeList=[Employee{id=1, lastName='黄伟', gender='男', mail='huangwei@knockatdatabase.com', department=null}, Employee{id=2, lastName='Huang', gender='?', mail='hensi163@163.com', department=null}]}
[Employee{id=1, lastName='黄伟', gender='男', mail='huangwei@knockatdatabase.com', department=null}, Employee{id=2, lastName='Huang', gender='?', mail='hensi163@163.com', department=null}]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@31368b99]
DEBUG [main] - Returned connection 825658265 to pool.

三 小结

association,见名知意,用于定义关联对象。通常用于一对一的对象关联场景;搭配javaType标签使用,内容为目标类的全类名;

collection,见名知意,用于定义关联集合类型。用于一对多的对象关联场景;搭配ofType标签使用,其值也为目标类的全类名;

四 补充

当然,该示例执行前,要准备好数据库里的表数据的关联关系。

mysql> select * from tbl_dept;
+----+-----------+
| id | dept_name |
+----+-----------+
|  1 | 市场部    |
|  2 | 财务部    |
+----+-----------+
2 rows in set (0.21 sec)

mysql> select * from tbl_employee;
+----+-----------+--------+------------------------------+------+
| id | last_name | gender | email                        | did  |
+----+-----------+--------+------------------------------+------+
|  1 | 黄伟      | 男     | huangwei@knockatdatabase.com |    1 |
|  2 | Huang     | ?      | hensi163@163.com             |    1 |
|  4 | Huang     | 男     | hensi163@163.com             |    2 |
|  5 | Huang     | 男     | hensi163@163.com             |    2 |
|  6 | Huang     | 男     | hensi163@163.com             |    2 |
|  7 | Huang     | 男     | hensi163@163.com             |    2 |
|  8 | Huang     | 男     | hensi163@163.com             |    2 |
|  9 | Huang     | 男     | hensi163@163.com             |    2 |
| 10 | Huang     | 男     | hensi163@163.com             | NULL |
+----+-----------+--------+------------------------------+------+
9 rows in set (0.00 sec)

mysql>

留言