MyBatis⑥ResultMap、多表查询

1、ResultMap 介绍

1.1、结果映射

结果映射:将 DQL 查询结果的字段映射到 Java 属性

原则自动映射简单关系,ResultMap 配置复杂关系

  • 简单关系:名称相同,类型匹配。
  • 复杂关系
    • 名称不相同:配置名称映射关系。
    • 类型不匹配:多表查询。

1.2、ResultMap 配置

注:只需配置复杂关系,MyBatis 会自动映射简单关系。

  • 配置:ResultMap 建立数据库表字段与 Java 实体类属性的映射关系。
  • 使用:select 标签的 resultMap 属性,引入对应 id 的 resultMap。

1.2.1、标签属性

  • resultMap

    • id:标识 ResultMap。
    • type:数据库表所映射的 Java 实体类(全限类名或别名)。
  • result

    • column:数据库表的字段名(或别名)。

    • property:字段所映射的 Java 属性名

      <resultMap id="" type="映射的实体类名">
          <result column="数据库表字段" property="实体类属性"/>
          <result column="数据库表字段" property="实体类属性"/>
      </resultMap>
      

1.2.1、使用示例

名称不相同

  • MyBatis 核心配置文件settings,可开启自动映射 mapUnderscoreToCamelCase
  • 本质是建立 ResultMap,处理数据库表字段和实体类属性之间的映射关系。

示例:将数据库表的 user_id 映射为 Java 实体类的 userId。

<resultMap id="userMap" type="user">
    <result column="user_id" property="userId"/>
</resultMap>

<select id="getUserById" resultMap="userMap">
    SELECT user_id, name, password
    FROM t_user
</select>

类型不匹配

涉及多表查询

  • 多对一:多个 A 对应一个 B(关联)
  • 一对多:一个 A 对应多个 B(集合)

2、多表查询

一对多和多对一,是基于不同角度描述的相对关系。

示例:部门和员工的关系。

  • 多对一:多个员工属于一个部门(关联)
  • 一对多:一个部门包含多个员工(集合)

数据库表

“一” 的数据库表中建立 “多” 的逻辑外键。

  • 部门表

    image-20220408183721367

  • 员工表:建立逻辑外键,即部门 ID

    image-20220408183751411

实体类

“一” 的实体类中建立 “多” 的对象类型(而不仅仅是主键)。

  • 部门类

    public class Department {
        private String deptId;
        private String name;
    }
    
  • 员工类:通过 Department 类表示部门,而不是 deptId。

    public class Employee {
        private String empId;
        private String name;
        private Department department;
    }
    

2.1、多对一

需求:查询所有员工,及所属的部门信息。

List<Employee> listEmployees();
  • 在数据库表中以 dept_id 表示,在实体类中以 Department 表示。
  • 通过 resultMap 的 association 标签,建立关联关系。
    • 结合子查询
    • 结合联表查询

2.1.1、子查询

EmployeeMapper.xml

  • listEmployees

    • 查询 employee 表
    • 引用 resultMap,而不是 resultType
  • resultMap - association:建立关联关系,将数据库表的 dept_id 映射为 Department

    • column:数据库表的字段名
    • property:实体类的属性名。
    • javaType:映射的 Java 类型(全限类名或别名)。
    • select:引用子查询
  • 子查询#{} 占位符参数,由 resultMap 的 column 提供。

    <select id="listEmployees" resultMap="employeeMap">
        SELECT emp_id, name, dept_id
        FROM study_mysql.t_employee
    </select>
    
    <resultMap id="employeeMap" type="indi.jaywee.pojo.Employee">
        <association column="dept_id" property="department"
                     javaType="indi.jaywee.pojo.Department"
                     select="getDepartmentById"/>
    </resultMap>
    
    <select id="getDepartmentById" resultType="indi.jaywee.pojo.Department">
        SELECT dept_id, name
        FROM study_mysql.t_department
        WHERE dept_id = #{dept_id}
    </select>
    

等价 SQL

结合子查询的方式,相当于:

SELECT e.emp_id  AS e_id,
       e.name    AS e_name,
       e.dept_id AS d_id,
       (SELECT d.name
        FROM t_department
        WHERE dept_id = d_id)
FROM t_employee AS e;

2.1.2、联表查询

EmployeeMapper.xml

  • listEmployees

    • 联表查询:查询 employee 和 department 表,起别名(因为两个表有同名属性)
    • 引用 resultMap,而不是 resultType。
  • resultMap

    • result

      • column:数据库表的字段名。
      • property:实体类的属性名。
    • association:建立关联关系,将数据库表的 dept_id 映射为 Department。

      • property:实体类的属性名。

      • javaType:映射的 Java 类型(全限类名或别名)。

        <select id="listEmployees" resultMap="employeeMap">
            SELECT e.emp_id  AS e_id,
                   e.name    AS e_name,
                   e.dept_id AS d_id,
                   d.name    AS d_name
            FROM study_mysql.t_employee AS e
                     LEFT JOIN study_mysql.t_department AS d
                               ON e.dept_id = d.dept_id
        </select>
        
        <resultMap id="employeeMap" type="indi.jaywee.pojo.Employee">
            <result column="e_id" property="empId"/>
            <result column="e_name" property="name"/>
        
            <association property="department" javaType="indi.jaywee.pojo.Department">
                <result column="d_id" property="deptId"/>
                <result column="d_name" property="name"/>
            </association>
        </resultMap>
        

2.2、一对多

需求:查询所有部门,及部门下的所有员工信息。

List<Department> listDepartments();
  • 数据库 department 表中没有关于员工的字段,需要通过 dept_id 查询 employee 表。
  • 通过 resultMap 的 collection 标签,建立集合关系。
    • 结合子查询
    • 结合联表查询

实体类

  • 员工:此处省略对部门属性的配置。

  • 部门:添加 List 成员变量,表示部门所包含的员工。

    private List<Employee> employeeList;
    

2.2.1、子查询

DepartmentMapper.xml

  • listDepartments

    • 查询 deparment 表
    • 引用 resultMap,而不是 resultType
  • resultMap - collection:建立集合关系

    • column:数据库表的字段名,作为子查询的查询条件。
    • property:实体类的属性名。
    • javaType:集合类型,可省略(全限类名或别名)
    • ofType:实际映射的 Java 类型(全限类名或别名)
    • select:引用子查询
  • 子查询#{} 占位符参数,由 resultMap 的 column 提供。

    <select id="listDepartments" resultMap="departmentMap">
        SELECT emp_id, name, dept_id
        FROM study_mysql.t_employee
    </select>
    
    <resultMap id="departmentMap" type="indi.jaywee.pojo.Department">
        <collection column="dept_id" property="employeeList"
                    javaType="java.util.List" ofType="indi.jaywee.pojo.Employee"
                    select="listEmployeesByDeptId"/>
    </resultMap>
    
    <select id="listEmployeesByDeptId" resultType="indi.jaywee.pojo.Employee">
        SELECT emp_id, name
        FROM study_mysql.t_employee
        WHERE dept_id = #{dept_id}
    </select>
    

2.2.2、联表查询

DepartmentMapper

  • listEmployees

    • 联表查询:查询 department 和 employee 表,起别名(因为两个表有同名属性)
    • 引用 resultMap,而不是 resultType
  • resultMap

    • result

      • column:数据库表的字段名
      • property:实体类的属性名。
    • collection:建立集合关系

      • property:实体类的属性名。

      • javaType:集合类型,可省略(全限类名或别名)。

      • ofType:实际映射的 Java 类型(全限类名或别名)

        <select id="listDepartments" resultMap="departmentMap">
            SELECT d.dept_id AS d_id,
                   d.name    AS d_name,
                   e.emp_id  AS e_id,
                   e.name    AS e_name
            FROM study_mysql.t_department AS d
                     LEFT JOIN study_mysql.t_employee AS e
                               ON d.dept_id = e.dept_id
        </select>
        
        <resultMap id="departmentMap" type="indi.jaywee.pojo.Department">
            <result column="d_id" property="deptId"/>
            <result column="d_name" property="name"/>
        
            <collection property="employeeList" ofType="indi.jaywee.pojo.Employee">
                <result column="e_id" property="empId"/>
                <result column="e_name" property="name"/>
            </collection>
        </resultMap>
        

2.3、小结

多对一和一对多关系,是基于不同角度描述的相对关系。

  • 多对一:关联(association),javaType 表示映射对象。
  • 一对多:集合(collection),ofType 表示映射对象。

通过 resultMap 标签,建立复杂关系的映射关系。

  • 子查询
    1. 查出当前表的属性,封装到当前对象。
    2. 根据逻辑外键进行子查询,在子查询中封装关联对象。
  • 联表查询:推荐
    1. 查出所有表的属性,起别名。
    2. 通过 resultMap 配置所有映射关系。
posted @ 2021-07-28 14:40  Jaywee  阅读(191)  评论(0编辑  收藏  举报

👇