MyBatis 框架ResultMap一对一查询

2021-10-28 0 By admin

MyBatis 框架中使用 ResultMap 包装SQL语言的结果集,ResultMap 可以帮助我们处理多表查询中一对一查询和一对多查询。

一、环境提前搭建

一个部门对应多个员工,一个员工对应一个部门的关系映射。

1.1、创建数据库表

// dept 部门表

CREATE TABLE `dept` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

// employee 员工表

CREATE TABLE `employee` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `did` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fkdid` (`did`),
  CONSTRAINT `fkdid` FOREIGN KEY (`did`) REFERENCES `dept` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

1.2、创建实体类

// 部门实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
    private Integer id;
    private String name;
}

// 员工实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
    private Integer id;
    private String name;
    // 多对一, 查询N方的同时获取到1方
    private Dept dept;
}

二、联合查询

通过一条联合多表的SQL查询语句,获取到多个 POJO 数据,并通过 ResultMap 映射到对应的对象中。

2.1、创建 Mapper 接口

// 部门接口

public interface DeptMapper {
}

// 员工接口

public interface EmployeeMapper {
    List<Employee> getAll();
}

2.2、Mapper.xml 映射文件

// 部门映射文件 DeptMapper.xml

<?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="org.hong.mapper.DeptMapper">
  <resultMap id="deptBase" type="org.hong.pojo.Dept">
    <id property="id" column="did"></id>
    <result property="name" column="dname"></result>
  </resultMap>
</mapper>

// 员工映射文件 EmployeeMapper.xml

<?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="org.hong.mapper.EmployeeMapper">

<!-- 创建一个只封装普通属性的resultMap映射规则 -->
  <resultMap id="employeeBase" type="org.hong.pojo.Employee">
    <id property="id" column="id"></id>
    <result property="name" column="name"></result>
  </resultMap>

<!-- 使用extends属性继承一个resultMap可以获得指定的resultMap定义过的映射规则, 
就可以省略普通属性, 只写级联属性的规则 -->
  <resultMap id="employee1" type="org.hong.pojo.Employee" extends="employeeBase">
<!-- 方式一: 联合查询, 级联属性封装结果 -->
    <result property="dept.id" column="did"></result>
<!-- 两张表都有name字段, 在进行封装的时候就会出现问题, 要么查询的时候取别名, 要么在建表的时候就避免 -->
    <result property="dept.name" column="dname"></result>
  </resultMap>

  <resultMap id="employee2" type="org.hong.pojo.Employee" extends="employeeBase">
<!--
方式二: 给指定联合的javaBean对象编写映射规则
    association:定义关联对象的封装规则
        property: 指定哪个属性是联合的对象
        javaType: 指定这个属性对象的类型[不能省略]
-->
    <association property="dept" javaType="org.hong.pojo.Dept">
      <id property="id" column="did"></id>
      <result property="name" column="dname"></result>
    </association>
  </resultMap>

  <resultMap id="employee3" type="org.hong.pojo.Employee" extends="employeeBase">
<!-- 方式三: 使用association节点的resultMap属性指定级联对象的映射规则, 而不是再写一份 -->
    <association property="dept" resultMap="org.hong.mapper.DeptMapper.deptBase"></association>
  </resultMap>

<!-- 查询Employee的同时查询出对应Dept, 此时使用resultType就做不到了, 需要使用resultMap引用自自定义的映射规则 -->
  <select id="getAll" resultMap="employee3">
    <!-- 内连接 -->
    select e.*, d.id did, d.name dname from employee e inner join dept d on e.did = d.id
  </select>
</mapper>

三、嵌套查询

通过多次查询的方式,将每次查询的结果映射到对应的POJO中。

3.1、创建 Mapper 接口

// 部门 Mapper 接口

public interface DeptMapper {
    Dept get(int id);
}

// 员工 Mapper 接口

public interface EmployeeMapper {
    List<Employee> getAll();
}

3.2、Mapper.xml 映射文件

// 部门 DeptMapper.xml

<?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="org.hong.mapper.DeptMapper">
  <select id="get" resultType="org.hong.pojo.Dept">
    select * from dept where id = #{id}
  </select>
</mapper>

// 员工 EmployeeMapper.xml

<?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="org.hong.mapper.EmployeeMapper">
  <!--
    思路:
      1.查询所有员工的信息
      2.根据查询出来的员工的did查询对应的部门
  -->
  <resultMap id="employee" type="org.hong.pojo.Employee">
    <id property="id" column="id"></id>
    <result property="name" column="name"></result>
    <!--
      association:定义关联对象的封装规则
        select: 表明当前属性是调用select指定的方法查出的结果
        column: 指定将那一列的值传给select
   -->
    <association property="dept"
       column="did"
       javaType="org.hong.pojo.Dept"
       select="org.hong.mapper.DeptMapper.get"></association>
  </resultMap>
    <!-- 查询Employee的同时查询出对应Dept, 此时使用resultType就做不到了, 需要使用resultMap -->
  <select id="getAll" resultMap="employee">
    select * from employee
  </select>
</mapper>