美文网首页Java 杂谈我爱编程
MyBatis | 映射文件之 ResultMap(二)

MyBatis | 映射文件之 ResultMap(二)

作者: EclipseO2 | 来源:发表于2018-07-27 11:25 被阅读0次

    在上一篇文章 MyBatis | 映射文件之 ResultMap(一)中,简述了如何使用 ResultMap,以及如何使用 ResultMap 进行一对一的关联查询。这一篇我将说明如何使用 ResultMap 进行一对多的关联查询

    一、说明与准备

    为了便于学习,我仍然会贴出表结构和 POJO 的设计,下面是实验前的环境搭建

    employee 的 dept_id 关联 department 表的 id 字段,即 id 是 dept_id 的外键。这和上一篇的创建是一致的

    employee表
    department 表
    Employee.java
    public class Employee {
    
        private Integer id;
        private String lastName;
        private String email;
        private Integer gender;
        private Department department;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
            ...
    }
    

    Department:这里我设置了一个类型为 Employee 的 List 集合,对应数据库表中一个部门可以有多个员工

    public class Department {
    
        private Integer id;
        private String departName;
        private List<Employee> employees;
        
        public void setEmployees(List<Employee> employees) {
            this.employees = employees;
        }
        
        public List<Employee> getEmployees() {
            return employees;
        }
            ...
    }
    

    二、使用 ResultMap 进行一对多关联查询

    需求是,使用 sql 语句,查询出每个部门的信息,以及每个部门所关联的员工信息。由于一个部门对应多个员工,即一对多,这里我们使用 LEFT JOIN 对字段进行连接

    1. 使用 collection 进行两张表的关联查询

    类似于上一篇中介绍的一对一的关联查询,不过上一篇中关联的是一个对象,不这里关联的是一个集合。至于 collection,我会结合代码进行讲解

    ①. 首先创建一个集合类
    DepartmentMapper.java

    public interface DepartmentMapper {
        public Department getDepartmentAndList(Integer id);
    }
    



    ②. 配置 sql 映射文件
    下面是 DepartmentMapper.xml 的配置信息,sql 语句如下,当然是使用外键关联

    <select id="getDepartmentAndList" resultMap="dept">
        SELECT d.id did, d.depart_name, e.id eid, e.last_name, email, gender 
        FROM department d 
        LEFT JOIN employee e 
        ON d.id = e.dept_id 
        WHERE d.id = #{id}
    </select>
    

    接下来写 resultMap 的配置:外层的 id 和 result 标签,是配置 Department 类(表)的,collection 标签里面的 id 和 result 标签,都是用来配置与 Department 类关联的 Employee 类(表)的。(PS:由于我在 mybatis.xml 主配置文件中配置了使用别名,因此类型都是以别名显示。否则需要全类名。)

    collection 标签里定义的集合对象,这里定义的是 Employee 类型的集合
    property:指定 Department 对象里面包含的 Employee 集合对象,即 List<Employee> employees
    ofType:指定集合的类型

    <!-- 使用嵌套结果集的方式, 使用 collection 标签定义关联的集合类型的封装规则 -->
    <resultMap type="Department" id="dept">
        <!-- Deparment 类的配置 -->
        <id column="id" property="id"/>
        <result column="depart_name" property="departName"/>
        
        <!-- Employee 类的配置 -->
        <collection property="employees" ofType="Employee">
            <id column="id1" property="id"/>
            <result column="last_name" property="lastName"/>
            <result column="email" property="email"/>
            <result column="gender" property="gender"/>
        </collection>
    </resultMap>
    

    ③. 结果
    测试语句我不写了,我们传入 Employee 的 id 为 1,直接贴出结果

    Department [id=1, departName=开发部]
    [Employee [id=1, lastName=Tom, email=tom@126.com, gender=0], 
    Employee [id=2, lastName=Peter, email=peter@qq.com, gender=1], 
    Employee [id=7, lastName=ljk, email=lkj@123.com, gender=1], 
    Employee [id=15, lastName=lkj, email=lkj@123.com, gender=2]]
    

    同时贴出使用同样 sql 语句和同样 id 的数据库查询的结果

    +-----+-------------+------+-----------+--------------+--------+
    | did | depart_name | eid  | last_name | email        | gender |
    +-----+-------------+------+-----------+--------------+--------+
    |   1 | 开发部      |    1 | Tom       | tom@126.com  |      0 |
    |   1 | 开发部      |    2 | Peter     | peter@qq.com |      1 |
    |   1 | 开发部      |    7 | ljk       | lkj@123.com  |      1 |
    |   1 | 开发部      |   15 | lkj       | lkj@123.com  |      2 |
    +-----+-------------+------+-----------+--------------+--------+
    

    可以看到,使用 resultMap 查询出来的结果和数据库查询的结果一致,而且 Employee 确实是以 List 集合的形式出现的。

    ⭐⭐⭐遇到的坑:
    在查询的过程中,遇到了一个毕竟大的坑🕳,当时找了快几个小时╯︿╰,这里说明一下,防患于未来。。
    先斩后奏把。column 里面的值一定要与查询出来的列名相一致, 如果使用列的别名, 则 column 的值就是列的别名

    拿上面的 sql 为例,我们看一下使用别名查询出来的列名

    | did | depart_name | eid | last_name | email | gender |
    

    以 id 这个字段为例子,我们注意一下 resultMap 里面配置的两个 id 标签对应的 column 对应的值,可以看到对应的是 sql 语句(SELECT d.id did, e.id eid ... FROM department d...)中设置的别名 dideid

    <resultMap type="Department" id="dept">
        <id column="did" property="id"/>
        ...
        <collection property="employees" ofType="Employee">
            <id column="eid" property="id"/>
            ....
        </collection>
    </resultMap>
    

    如果你没有设置别名(SELECT d.id, e.id ... FROM department d...),同时你在两个 id 标签的 column 直接填 id,那么就会出问题。。血的教训😭

    | id | depart_name | id1 | last_name | email | gender |
    

    不用别名查询出来的表的列名结构是这样的,如果真要用,可以这样配置。这样也是可以查询出结果的,不过并不推荐。还是使用别名把!!!

    <resultMap type="Department" id="dept">
        <id column="d1" property="id"/>
        ...
        <collection property="employees" ofType="Employee">
            <id column="id1" property="id"/>
            ....
        </collection>
    </resultMap>
    
    2. 使用 collection 进行两张表的分布查询

    使用 association 进行分布查询,实则分三步:

    1. 先根据部门 id 查询出部门所有信息:select * from department where id = ?
    2. 根据部门查询出来的 id(外键),用于查询部门对应的多个员工信息:select * from employee where dept_id = ?
    3. 将员工信息关联到部门信息

    先创建一个接口类

    public interface DepartmentMapper {
        public Department getDepartmentStep(Integer id);
    }
    

    查询部门 Department 类的配置

    <select id="getDepartmentStep" resultMap="empStep">
        select id, depart_name from department where id = #{id}
    </select>
    

    查询员工 Employee 类的配置

    <select id="getEmployeeByDeptId" resultType="Employee">
        select id, last_name, gender, email, dept_id from employee where dept_id = #{deptId}
    </select>
    

    配置 resultMap,注意 collection 中的 column 属性对应数据库中的列名

    <resultMap type="Department" id="empStep">
        <!-- Department 类的配置 -->
        <id column="id" property="id"/>
        <result column="depart_name" property="departName"/>
        
        <!-- 
            使用 collection 定义分段的集合类型的属性 
         -->
        <collection property="employees" 
            select="edu.just.mybatis.dao.EmployeeMapper.getEmployeeByDeptId"
            column="id">
        </collection>
    </resultMap>
    

    结果:

    [Employee [id=1, lastName=Tom, email=tom@126.com, gender=0, department=null], 
    Employee [id=2, lastName=Peter, email=peter@qq.com, gender=1, department=null], 
    Employee [id=7, lastName=ljk, email=lkj@123.com, gender=1, department=null], 
    Employee [id=15, lastName=lkj, email=lkj@123.com, gender=2, department=null]]
    
    3. 使用延迟加载

    collection 标签中的延迟加载比较简单,直接在 collection 里面设置 fetchType 属性值为 lazy 即可
    fetchType="lazy" 表示使用延迟加载
    fetchType="eager" 表示立即加载

    <resultMap type="Department" id="empStep">
        ...
        <collection property="employees" 
            ...
            fetchType="lazy">
        </collection>
    </resultMap>
    

    相关文章

      网友评论

        本文标题:MyBatis | 映射文件之 ResultMap(二)

        本文链接:https://www.haomeiwen.com/subject/jlhwmftx.html