自定义resultMap映射处理(字段和属性的映射关系、一对一、多对一、一对多、多对多映射处理)

自定义resultMap映射处理

1.resultMap 处理字段和属性的映射关系

  • emp表
    在这里插入图片描述
  • Emp类相关属性(有参无参构造方法、提供set、get、重写toString)
private Integer empId; //员工id
private String empName; //员工姓名
private Integer age; //员工年龄
private String sex; //员工性别
  • EmpMapper
/**
 * 根据id查询员工
 * @param empId
 * @return
 */
Emp getEmpByEmpId(@Param("empId") Integer empId);
<?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.qcby.mapper.EmpMapper">
    <!--Emp getEmpByEmpId(@Param("empId") Integer empId);-->
    <select id="getEmpByEmpId" resultType="emp">
        select * from emp where emp_id=#{empId}
    </select>
</mapper>
@Test
public void testGetEmpByEmpId() {
    Emp empByEmpId = empMapper.getEmpByEmpId(1);
    System.out.println(empByEmpId);
}

如果字段名和实体类中的属性名不一致的情况下,可以通过resultMap 设置自定义映射。

什么是字段名和实体类中的属性名不一致,见下图
在这里插入图片描述
在这里插入图片描述
不一致就无法正确查询

解决方法:

(1)可以通过为字段起别名的方式,别名起成和属性名一致。保证字段名和实体类中的属性名一致
在这里插入图片描述

<!--Emp getEmpByEmpId(@Param("empId") Integer empId);-->
<select id="getEmpByEmpId" resultType="emp">
    <!--select * from emp where emp_id=#{empId}-->
    select emp_id empId,emp_name empName,age,sex from emp where emp_id = #{empId}
</select>

(2)如果字段名和实体类中的属性名不一致的情况下,但是字段名符合数据库的规则(使用_ ),实体类中使用的属性名符合java 的规则(使用驼峰命名),可以在 MyBatis 的核心配置文件 mybatis-config.xml 中设置一个全局配置信息mapUnderscoreToCamelCase,将其设置为true,便可以在查询表中的数据时,自动将带下划线“ _ ”的字段名转为驼峰命名
如:user name:userName
emp id:empld

<settings>
    <!--将数据库字段名的下划线映射为驼峰-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--Emp getEmpByEmpId(@Param("empId") Integer empId);-->
    <select id="getEmpByEmpId" resultType="emp">
        select * from emp where emp_id=#{empId}
    </select>

(3)使用resutlMap自定义映射处理

resultMap:设置自定义的映射关系
id:唯一标识(与resultMap设置的名称对应)
type:处理映射关系的实体类的类型 一般使用MyBatis的别名

常用的标签
	id:处理主键和实体类中属性的映射关系
    result:处理普通字段(主键之外的字段)和实体类中属性的映射关系
    column:设置映射关系中的字段名,必须是sql查询出的某个字段(否则查询出来的结果为null)
    property:设置映射关系中的属性的属性名,必须是处理的实体类型中的属性名

“column:设置映射关系中的字段名,必须是sql查询出的某个字段(否则查询出来的结果为null)”:
在这里插入图片描述
”property:设置映射关系中的属性的属性名,必须是处理的实体类型中的属性名“
在这里插入图片描述

<!--Emp getEmpByEmpId(@Param("empId") Integer empId);-->
<select id="getEmpByEmpId" resultMap="empResultMap">
    <!--select * from emp where emp_id=#{empId}-->
</select>

<resultMap id="empResultMap" type="emp">
        <id property="empId" column="emp_id"/>
        <result property="empName" column="emp_name"/>
        <result property="sex" column="sex"/>
        <result property="age" column="age"/>
</resultMap>

在这里插入图片描述

2. 一对一映射处理

以人与身份证号为例

创建person表和idcard表

在这里插入图片描述
两张表中数据
在这里插入图片描述
创建实体类,添加上相应的有参无参构造方法、get、set、toString方法

  • IdCard类
private Integer id; //主键id
private String code; //身份证号码
  • Person类
private Integer id; //主键id
private String name; //姓名
private Integer age; //年龄
private String sex; //性别

private IdCard card; //不写外键的信息,而是直接让人员关联证件

sql语句

SELECT person.*, idcard.`code` FROM person,idcard WHERE person.card_id=idcard.id AND person.id=1
  • 测试类
/**
 * 测试类
 */
public class ResultMapTest {
    private SqlSession sqlSession = null;
    private EmpMapper empMapper = null;
    private PersonMapper personMapper = null;

    @Before
    public void init() {
//        1.获取sqlsession对象
        sqlSession = SqlSessionUtil.getSqlSession();
//        2.获取代理实现类对象(因为接口是不能创建实例对象的,所以此处用的是代理实现类对象)
        empMapper = sqlSession.getMapper(EmpMapper.class);
        personMapper = sqlSession.getMapper(PersonMapper.class);
    }

    @After
    public void destory() {
//        5.关闭资源
        sqlSession.close();
        SqlSessionUtil.closeInputStream();
    }
  • SqlSessionUtil
public class SqlSessionUtil {
    //getSqlSession()为静态方法,因此要给变量加上static才能在getSqlSession()中使用
    private static InputStream inputStream = null;

    //静态方法,方便别的类直接调用
    public static SqlSession getSqlSession() {
        SqlSession sqlSession = null;
        try {
//        1.获取核心配置文件的输入流
            //(可能会出现异常,因为此方法会被其他类调用,所以选择内部try-catch处理异常)
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//        2.获取sqlsessionFactoryBuilder对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//        3.获取sqlsessionFactory对象
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
//        4.获取sqlsession对象(默认为false,不会自动提交对象;改为true就会自动提交)
            sqlSession = sqlSessionFactory.openSession(true);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sqlSession;
    }
    
    public static void closeInputStream() {
        //关闭文件可能关闭成功也可能关闭失败,因此使用try-catch处理一下
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

1.1 级联

创建mapper文件

public interface PersonMapper {
    /**
     * 根据id查询人员信息
     * @param id
     * @return
     */
    Person findPersonById(@Param("id") Integer id);
}

要返回的是Person中的四个属性+IdCard中的code属性,没有相应的实体类全部包含这五个属性,因此使用resultMap而不使用resultType
在这里插入图片描述

<!--    级联方式-->
    <!--Person findPersonById(@Param("id") Integer id);-->
    <!--IdCard中的id对我们来说没有意义,我们要的是相应的code-->
    <select id="findPersonById" resultMap="IdCardWithPersonResult">
        SELECT person.*, idcard.`code` FROM person,idcard
        WHERE person.card_id=idcard.id
        AND person.id=1
    </select>
    <!--返回person类型对象-->
    <resultMap id="IdCardWithPersonResult" type="person">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <result property="sex" column="sex"/>
        <result property="card.id" column="id"/>
        <result property="card.code" column="code"/>
    </resultMap>

在这里插入图片描述

1.2 association

Person findPersonById2(@Param("id") Integer id);
<!--    association-->
    <!--Person findPersonById2(@Param("id") Integer id);-->
    <select id="findPersonById2" resultMap="IdCardWithPersonResult2">
        SELECT person.*, idcard.`code` FROM person,idcard
        WHERE person.card_id=idcard.id
        AND person.id=1
    </select>
    <resultMap id="IdCardWithPersonResult2" type="person">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <result property="sex" column="sex"/>
        <association property="card" javaType="IdCard">
            <id property="id" column="id"/>
            <result property="code" column="code"/>
        </association>
    </resultMap>

在这里插入图片描述

@Test
public void testFindPersonById2() {
    Person person = personMapper.findPersonById2(1);
    System.out.println(person);
}

1.3 分步查询

在这里插入图片描述

第一步
SELECT * FROM person WHERE id=1
  • PersonMapper
Person findPersonById3(@Param("id") Integer id);
  • PersonMapper.xml
<!--    分步查询第一步-->
    <!--Person findPersonById3(@Param("id") Integer id);-->
    <select id="findPersonById3" resultMap="IdCardWithPersonResult3">
        SELECT * FROM person WHERE id=#{id}
    </select>
    <resultMap id="IdCardWithPersonResult3" type="person">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <result property="sex" column="sex"/>

        <association property="card" javaType="idCard" column="card_id"
            select="com.qcby.mapper.IdCardMapper.findCodeById">
        </association>
    </resultMap>
第二步
  • IdCardMapper
public interface IdCardMapper {
    /**
     * 分步查询第二步
     * 根据id查询证件信息
     * @param id
     * @return
     */
    IdCard findCodeById(@Param("id") Integer id);
}
  • IdCardMapper.xml
<mapper namespace="com.qcby.mapper.IdCardMapper">
    <!--分步查询第二步-->
    <!--IdCard findCodeById(@Param("id") Integer id);-->
    <select id="findCodeById" resultType="idCard">
        SELECT * FROM idcard WHERE id=#{id}
    </select>
</mapper>

在这里插入图片描述
运行结果
在这里插入图片描述

1.4 association相关属性

association 处理一对一或者多对一的映射关系(处理的是实体类类型的属性)

property 设置需要处理映射关系的属性的属性名

javaType 设置需要处理的属性的类型

column 第一步传递给第二步的字段,映射关系的表关联的字段

3. 多对一映射处理

以员工和部门为例(多个员工可以有同一个部门)
在这里插入图片描述

创建员工和部门两个表
在这里插入图片描述

  • 部门类
/**
 * 部门表
 */
public class Dept {
    private Integer deptId; //部门id
    private String deptName; //部门名称
}
  • 员工类
/**
 * 员工表
 */
public class Emp {
    private Integer empId; //员工id
    private String empName; //员工姓名
    private Integer age; //员工年龄
    private String sex; //员工性别

    //外键 (不写相应的外键名而直接写类)
    private Dept dept;
}

sql

SELECT emp.*, dept.* FROM emp LEFT JOIN dept ON emp.dept_id=dept.dept_id WHERE emp.emp_id=1

2.1 级联

/**
 * 通过员工id获取员工以及其对应的部门信息
 */
Emp getEmpAndDeptByEmpId(@Param("id") Integer id);
<!--Emp getEmpAndDeptByEmpId(@Param("id") Integer id);-->
<select id="getEmpAndDeptByEmpId" resultMap="empAndDeptResultMap">
    SELECT emp.*, dept.*
    FROM emp
    LEFT JOIN dept ON emp.dept_id=dept.dept_id
    WHERE emp.emp_id=#{id}
</select>
<resultMap id="empAndDeptResultMap" type="emp">
    <id column="emp_id" property="empId"/>
    <result column="emp_name" property="empName"/>
    <result column="age" property="age"/>
    <result column="sex" property="sex"/>
    <result column="dept_id" property="dept.deptId"/>
    <result column="dept_name" property="dept.deptName"/>
</resultMap>
@Test
public void testGetEmpAndDeptByEmpId() {
    Emp emp = empMapper.getEmpAndDeptByEmpId(1);
    System.out.println(emp);
}

在这里插入图片描述

2.2 association

Emp getEmpAndDeptByEmpId2(@Param("id") Integer id);
<!--Emp getEmpAndDeptByEmpId2(@Param("id") Integer id);-->
<select id="getEmpAndDeptByEmpId2" resultMap="empAndDeptResultMap2">
    SELECT emp.*, dept.*
    FROM emp
    LEFT JOIN dept ON emp.dept_id=dept.dept_id
    WHERE emp.emp_id=#{id}
</select>
<resultMap id="empAndDeptResultMap2" type="emp">
    <id column="emp_id" property="empId"/>
    <result column="emp_name" property="empName"/>
    <result column="age" property="age"/>
    <result column="sex" property="sex"/>
    
    <association property="dept" javaType="dept">
        <id column="dept_id" property="deptId"/>
        <result column="dept_name" property="deptName"/>
    </association>
</resultMap>

2.3 分步查询

在这里插入图片描述

第一步

根据员工id查询员工信息

  • emp接口
/**
 * 通过分步查询来查询员工以及所对应部门信息的第一步
 */
Emp getEmpAndDeptByStep1(@Param("empId") Integer empId);
第二步

根据员工信息中查询到的dept_id查询部门信息

  • dept接口
/**
 * 通过分步查询来查询员工以及所对应部门信息的第二步:查询部门信息
 */
Dept getEmpAndDeptByStep2(@Param("deptId") Integer deptId);
  • emp映射文件中
<!--Emp getEmpAndDeptByStep1(@Param("empId") Integer empId);-->
<select id="getEmpAndDeptByStep1" resultMap="empAndDeptResultMap3">
    SELECT * FROM emp WHERE emp_id=#{empId}
</select>
<resultMap id="empAndDeptResultMap3" type="emp">
    <id property="empId" column="emp_id"/>
    <result property="empName" column="emp_name"/>
    <result property="age" column="age"/>
    <result property="sex" column="sex"/>

    <association property="dept" column="dept_id"
                 select="com.qcby.mapper.DeptMapper.getEmpAndDeptByStep2">
    </association>
</resultMap>
  • dept映射文件中
<!--Dept getEmpAndDeptByStep2(@Param("deptId") Integer deptId);-->
<select id="getEmpAndDeptByStep2" resultType="dept">
    SELECT * FROM dept WHERE dept_id=#{deptId}
</select>
  • 测试
@Test
public void testGetEmpAndDeptByStep() {
    Emp emp = empMapper.getEmpAndDeptByStep1(2);
    System.out.println(emp);
}

在这里插入图片描述

分步查询的优点:

​ 可以实现延迟加载(懒加载),但是必须在核心配置文件中设置全局配置信息

lazyLoadingEnabled:延迟加载的全局开关,当开启时(true),所有管理对象都会延迟加载。默认false

aggressiveLazyLoading :当开启时(true),任何方法的调用都会加载该对象的所有属性。否则(false),每个属性会按需加载,此时就可以实现按需加载,获取的数据是什么,就会执行相应的sql语句。默认false,此时可以通过associationcollection 中的fetchType="lazy(延迟加载) |eager(立即加载)"属性设置当前的分步查询是否使用延迟加载(默认fetchType=“lazy(延迟加载)”)
在这里插入图片描述

4. 一对多映射处理

没有级联方式的查询,只有集合collection和分步查询

查询一个部门,以及该部门中的多个员工的信息(一个部门中的多个员工信息)
在这里插入图片描述

collection

  • sql语句
SELECT * FROM dept LEFT JOIN emp ON dept.dept_id=emp.dept_id
WHERE dept.dept_id=#{deptId}
  • dept接口
/**
 * 查询部门以及部门中的员工信息
 * @param deptId
 * @return
 */
Dept getDeptAndEmpByDeptId(@Param("deptId") Integer deptId);
  • dept映射文件中
<!--Dept getDeptAndEmpByDeptId(@Param("deptId") Integer deptId);-->
<select id="getDeptAndEmpByDeptId" resultMap="deptAndEmpResultMap">
    SELECT *
    FROM dept
    LEFT JOIN emp ON dept.dept_id=emp.dept_id
    WHERE dept.dept_id=#{deptId}
</select>

<resultMap id="deptAndEmpResultMap" type="dept">
    <id property="deptId" column="dept_id"/>
    <result property="deptName" column="dept_name"/>

    <!--ofType:设置集合类型的属性中存储的数据的类型-->
    <collection property="emps" ofType="emp">
        <id property="empId" column="emp_id"/>
        <result property="empName" column="emp_name"/>
        <result property="age" column="age"/>
        <result property="sex" column="sex"/>
    </collection>
</resultMap>
  • 测试
@Test
public void testGetDeptAndEmpByDeptId() {
    Dept dept = deptMapper.getDeptAndEmpByDeptId(2);
    System.out.println(dept);
}

在这里插入图片描述

分步查询

在这里插入图片描述

第一步

根据dept_id查询部门信息

  • dept接口
/**
 * 通过分步查询进行查询部门及部门中的员工信息的第一步:查询部门信息
 * @param deptId
 * @return
 */
Dept getDeptAndEmpBystepOne(@Param("deptId") Integer deptId);
  • dept映射文件
<!--Dept getDeptAndEmpBystepOne(@Param("deptId") Integer deptId);-->
<select id="getDeptAndEmpBystepOne" resultMap="deptAndEmpResultMapByStep">
    SELECT * FROM dept WHERE dept_id=#{deptId}
</select>

<resultMap id="deptAndEmpResultMapByStep" type="dept">
    <id property="deptId" column="dept_id"/>
    <result property="deptName" column="dept_name"/>

    <collection property="emps" column="dept_id"
                select="com.qcby.mapper.EmpMapper.getDeptAndEmpBystepTwo">
    </collection>
</resultMap>
第二步

根据dept_id查询员工信息

  • emp接口
/**
 * 通过分步查询来查询部门以及所对应员工信息的第二步:查询员工信息
 * @param empId
 * @return
 */
Emp getDeptAndEmpBystepTwo(@Param("empId") Integer empId);
  • emp映射文件
<!--Emp getDeptAndEmpBystepTwo(@Param("empId") Integer empId);-->
<select id="getDeptAndEmpBystepTwo" resultType="emp">
    SELECT * FROM emp WHERE dept_id=#{empId}
</select>
  • 测试类
@Test
public void testGetDeptAndEmpBystep() {
    Dept dept = deptMapper.getDeptAndEmpBystepOne(2);
    System.out.println(dept);
}

在这里插入图片描述

5. 多对多映射处理

以商品和订单为例(同一种商品可能在多个订单里,一个订单里可以有很多个商品)

多对多需要创建中间表
在这里插入图片描述

分步查询

  • sql语句

在这里插入图片描述

第一步
  • orders接口
/**
 * 通过分步查询进行查询订单以及订单中的商品信息的第一步:查询订单
 * @param id
 * @return
 */
List<Orders> findOrdersWithProductByStep1(@Param("id") Integer id);
第二步
  • product接口
/**
 * 通过分步查询进行查询订单以及订单中的商品信息的第二步:查询商品
 * @param id
 * @return
 */
List<Product> findOrdersWithProductByStep2(@Param("id") Integer id);
  • orders映射文件
<!--List<Orders> findOrdersWithProductByStep1(@Param("id") Integer id);-->
<select id="findOrdersWithProductByStep1" resultMap="OrdersWithProductByStep">
    SELECT * FROM orders WHERE id=#{id}
</select>

<resultMap id="OrdersWithProductByStep" type="orders">
    <id property="id" column="id"/>
    <result property="number" column="number"/>
    <collection property="productList" column="id" ofType="product"
                select="com.qcby.mapper.ProductMapper.findOrdersWithProductByStep2">
    </collection>
</resultMap>
  • product映射文件
<!--List<Product> findOrdersWithProductByStep2(@Param("id") Integer id);-->
<select id="findOrdersWithProductByStep2" resultType="product">
    SELECT * FROM product WHERE id in(
        SELECT product_id FROM ordersitem WHERE orders_id=#{id}
        )
</select>
  • 测试类
@Test
public void testFindOrdersWithProductByStep() {
    List<Orders> orders = ordersMapper.findOrdersWithProductByStep1(1);
    for (Orders order : orders) {
        System.out.println(order);
    }
}

在这里插入图片描述

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值