Mybatis - 一对多/多对一映射


前言

本文以 SpringBoot 整合 Mybatis 为例,讲解项目中一对多和多对一的简单用法

项目结构

在这里插入图片描述

一、数据库表

1. 员工表 t_emp

在这里插入图片描述

2. 部门表 t_dept

在这里插入图片描述

二、实体类

1. Emp 员工实体类(添加多对一属性)

@Data
public class Emp {
    
    

    private Integer eId;
    private String eName;
    private Integer age;
    private String sex;
    private String phone;
    private String email;

    // 多对一关系 后添加的属性
    private Dept dept;

}

2. dept 部门实体类(添加一对多属性)

@Data
public class Dept {
    
    

    private Integer dId;
    private String dName;
    private String dLocation;
    // private Emp emp1;
    // private Emp emp2;
    // private Emp emp3;
    // ... 可能出来0 ~ ? Emp对象  一对多关系 后添加的属性
    private List<Emp> emps;
    
}

三、配置文件,配置类

1. 配置文件 application.properties

# 数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai
# 数据库用户名
spring.datasource.username=root
# 数据库密码
spring.datasource.password=root

# 关联映射的配置(指定XML文件所在的位置)
mybatis.mapper-locations=classpath:mappers/*.xml
# 配置别名
mybatis.type-aliases-package=com.cy.mybatis.pojo.entity
# 开启驼峰映射 
mybatis.configuration.map-underscore-to-camel-case=true

# 日志
logging.level.com.cy.mybatis.mapper=debug

2. 配置类 MybatisConfig.java

@Configuration // 将它标注的类为配置类
@MapperScan("com.cy.mybatis.mapper")
public class MybatisConfig {
    
    
}

四、持久层接口

1. EmpMapper.java

public interface EmpMapper {
    
    

    // 根据员工id查询员工信息(包括部门信息)
    Map<String,Object> getObjectByIdToMap(@Param("eid") int eid);
    
	// 根据员工id查询员工信息(包括部门信息)
    Emp getEmpAndDeptById(@Param("eid") int eid);

}

2. DeptMapper.java

public interface DeptMapper {
    
    
    // 通过部门id查询部门所有信息(包含部门员工)
    Dept getDeptAndEmpById(@Param("did") int did);
}

五、xml映射文件

1. EmpMapper.xml(多对一)

1.1 级联

<?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.cy.mybatis.mapper.EmpMapper">
	
	<!-- 自定义映射关系  -->
    <resultMap id="empAndDeptResultMap" type="emp">
        <id column="e_id" property="eId"/>
        <result column="e_name" property="eName"/>
        <result column="age" property="age"/>
        <result column="sex" property="sex"/>
        <result column="phone" property="phone"/>
        <result column="email" property="email"/>
        <!-- 级联查询自定义映射关系  -->
        <result column="d_id" property="dept.dId"/>
        <result column="d_name" property="dept.dName"></result>
        <result column="d_location" property="dept.dLocation"></result>
    </resultMap>

    <select id="getEmpAndDeptById" resultMap="empAndDeptResultMap">
        select *
        from t_emp e
        join t_dept d
        on e.d_id=d.d_id
        where e.e_id = #{eid}
    </select>

</mapper>

测试输出结果:
在这里插入图片描述

1.2 association 标签 - 关联查询(常用)

<?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.cy.mybatis.mapper.EmpMapper">
	
	<-- 通过Map封装查询结果 -->
    <select id="getObjectByIdToMap" resultType="java.util.Map">
        select *
        from t_emp e
        join t_dept d
        on e.d_id=d.d_id
        where e.e_id = #{eid}
    </select>
	
	<!-- 自定义映射关系  -->
    <resultMap id="empAndDeptResultMap" type="emp">
        <id column="e_id" property="eId"/>
        <result column="e_name" property="eName"/>
        <result column="age" property="age"/>
        <result column="sex" property="sex"/>
        <result column="phone" property="phone"/>
        <result column="email" property="email"/>
        <!--
            association: 处理多对一的映射关系
                参数: property 需要处理多对一的映射关系的属性名称  Dept dept 中的dept
                     javaType(java类型) 该属性的类型 Dept dept 中的Dept
        -->
        <association property="dept" javaType="Dept">
            <id column="d_id" property="dId"></id>
            <result column="d_name" property="dName"></result>
            <result column="d_location" property="dLocation"></result>
        </association>
    </resultMap>

    <select id="getEmpAndDeptById" resultMap="empAndDeptResultMap">
        select *
        from t_emp e
        join t_dept d
        on e.d_id=d.d_id
        where e.e_id = #{eid}
    </select>

</mapper>

1.3 association 标签 - 分布查询(更常用)

  • 步骤一:EmpMapper.java

    public interface EmpMapper {
          
          
        /**
         * 通过分布查询: 查询员工以及员工所对应的部门信息
         * 分布查询第一步: 查询员工信息
         * @param eid 员工id
         * @return
         */
        Emp getEmpAndDeptByIdStepOne(@Param("eid") int eid);
    }
    
  • 步骤二:EmpMapper.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="com.cy.mybatis.mapper.EmpMapper">
    
        <resultMap id="EmpAndDeptByIdStepResultMap" type="emp">
            <id column="e_id" property="eId"/>
            <result column="e_name" property="eName"/>
            <result column="age" property="age"/>
            <result column="sex" property="sex"/>
            <result column="phone" property="phone"/>
            <result column="email" property="email"/>
            <--
        	 association: 处理多对一的映射关系
               参数: property 需要处理多对一的映射关系的属性名称  Dept dept 中的dept
                     select 设置分部查询的sql语句的唯一标识(namespace.SQLId或mapper接口的全限定名.方法名)
                     column 设置分部查询的条件(第二步查询需要的条件)
    		-->
            <association property="dept"
                         select="com.cy.mybatis.mapper.DeptMapper.getEmpAndDeptByIdStepTwo"
                         column="d_id"></association>
        </resultMap>
    
        <select id="getEmpAndDeptByIdStepOne" resultMap="EmpAndDeptByIdStepResultMap">
            select * from t_emp where e_id = #{eid}
        </select>
    </mapper>    
    
  • 步骤三:DeptMapper.java

    public interface DeptMapper {
          
          
        /**
         * 通过分布查询: 查询员工以及员工所对应的部门信息
         * 分布查询第二步: 通过did查询员工所对应的部门信息
         * @param did 部门id
         * @return
         */
        Dept getEmpAndDeptByIdStepTwo(@Param("did") int did);
    }
    
  • 步骤四: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="com.cy.mybatis.mapper.DeptMapper">
    
        <resultMap id="DeptResultMap" type="dept">
            <id column="d_id" property="dId"/>
            <result column="d_name" property="dName"/>
            <result column="d_location" property="dLocation"/>
        </resultMap>
    
        <select id="getEmpAndDeptByIdStepTwo" resultMap="DeptResultMap">
            select * from t_dept where d_id = #{did}
        </select>
    </mapper>
    
  • 步骤五:测试类测试 EmpMapperTests.java

    @SpringBootTest
    public class EmpMapperTests {
          
          
    
        @Autowired
        EmpMapper empMapper;
    
        @Test
        void testGetEmpAndDeptByIdStepOne() {
          
          
            Emp emp = empMapper.getEmpAndDeptByIdStepOne(1);
            System.out.println(emp);
        }
    }
    

    测试结果:

    在这里插入图片描述
    与之前的关联查询不同,这里执行的是两条SQL语句

2. DeptMapper.xml(一对多)

2.1 collection 标签 - 关联查询(常用)

<?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.cy.mybatis.mapper.DeptMapper">

    <!--
        collection: 处理一对多的映射关系
            参数: property 需要处理一对多的映射关系的属性名称  List<Emp> emps 中的emps
                 ofType(的类型) 该属性所对应的集合中存储的类型,集合中泛型的类型 List<Emp> emps 中的Emp
    -->
    <resultMap id="DeptAndEmpBResultMap" type="dept">
        <id column="d_id" property="dId"/>
        <result column="d_name" property="dName"/>
        <result column="d_location" property="dLocation"/>
        <collection property="emps" ofType="Emp">
            <id column="e_id" property="eId"/>
            <result column="e_name" property="eName"/>
            <result column="age" property="age"/>
            <result column="sex" property="sex"/>
            <result column="phone" property="phone"/>
            <result column="email" property="email"/>
        </collection>
    </resultMap>

    <select id="getDeptAndEmpById" resultMap="DeptAndEmpBResultMap">
        select *
        from t_emp
        join t_dept
        on t_emp.d_id=t_dept.d_id
        where t_dept.d_id = #{did}
    </select>

</mapper>

2.2 collection 标签 - 分步查询(更常用)

  • 持续更新…

六、测试类

1. EmpMapperTests

@SpringBootTest
public class EmpMapperTests {
    
    

    @Autowired
    EmpMapper empMapper;

    @Test
    void testGetObjectByIdToMap() {
    
    
        Map<String, Object> map = empMapper.getObjectByIdToMap(1);
        System.out.println(map);
    }

    @Test
    void testGetEmpAndDeptById() {
    
    
        Emp emp = empMapper.getEmpAndDeptById(1);       
        System.out.println(emp);
    }
}

输出结果
testGetObjectByIdToMap() 测试方法输出结果
在这里插入图片描述

testGetEmpAndDeptById() 测试方法输出结果
在这里插入图片描述

2. DeptMapperTests

@SpringBootTest
public class DeptMapperTests {
    
    

    @Autowired
    DeptMapper deptMapper;

    @Test
    void testGetDeptAndEmpById() {
    
    
        Dept dept = deptMapper.getDeptAndEmpById(1);
        System.out.println(dept);
    }
}

输出结果
在这里插入图片描述


总结

在处理这种一对多和多对一映射关系的业务中,我们可以通过两种方式去实现:

  • 封装到 Map 容器中
  • 添加自定义映射关系 ResultMap
    • 多对一
      • 实体类
        • 在多的那个实体类中(Emp)添加一的类型的属性 (Dept dept)
      • ResultMap 结果集映射 添加 <association> 标签
        • 属性
          • property 需要处理多对一的映射关系的属性名称 如:Dept dept 中的dept
          • javaType 该属性的类型 如:Dept dept 中的Dept
    • 一对多
      • 实体类
        • 在一的那个实体类中(Emp)添加多的类型的属性的集合 (List<Emp> emps)
      • ResultMap 结果集映射 添加 <collection> 标签
        • 属性
          • property 需要处理一对多的映射关系的属性名称 如:List<Emp> emps 中的emps
          • ofType(的类型) 该属性所对应的集合中存储的类型,集合中泛型的类型 如:List<Emp> emps 中的Emp

猜你喜欢

转载自blog.csdn.net/weixin_46030002/article/details/127565851