MyBatis映射一对多和多对一查询的几种方法及association和collection区别及应用场景,自定义映射resultMap标签和resultType标签的使用

目录

前言

自定义映射resultMap标签

resultType标签

准备sql表

多对一映射处理

1、级联方式处理映射关系

2、使用association处理映射关系

3、分步查询

①查询员工信息

②根据员工所对应的部门id查询部门信息

一对多映射处理

1、collenction

2、分步查询

①查询部门信息

②根据部门id查询部门中的所有员工

association和 collection


前言

MyBatis是一种持久层框架,用于简化数据库操作。在MyBatis中,映射是指将数据库中的数据映射到Java对象中的过程,而resultMap标签则用于定义映射规则。

resultMap标签是MyBatis中用于定义结果集映射规则的标签。它可以指定如何将查询结果映射到Java对象中的属性,包括列名和Java属性名的映射关系,以及复杂类型的映射规则。

一对多映射指的是一个Java对象中包含多个子对象的映射关系。在MyBatis中,可以使用collection标签来定义一对多映射的规则,指定父对象和子对象之间的映射关系,以及如何将查询结果映射到Java对象中。

多对一映射指的是多个Java对象中包含一个共同的父对象的映射关系。在MyBatis中,可以使用association标签来定义多对一映射的规则,指定子对象和父对象之间的映射关系,以及如何将查询结果映射到Java对象中。

自定义映射resultMap标签

resultMap是MyBatis中最强大的结果映射方式,它允许你自定义复杂的数据结构映射规则。当查询结果与实体类属性名不匹配或者需要处理关联关系时,可以使用此标签。resultMap会详细描述数据库表字段到Java对象属性之间的映射,以及嵌套结果集的映射。

若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射

resultMap:设置自定义映射属性,包含有以下几个标签:

id:表示自定义映射的唯一标识

type:查询的数据要映射的实体类的类型子标签:

id:设置主键的映射关系

result:设置普通字段的映射关系

association:设置多对一的映射关系

collection:设置一对多的映射关系属性

property:设置映射关系中实体类中的属性名

column:设置映射关系中表中的字段名

resultType标签

相对于resultMap,resultType标签提供了更为简洁的结果映射方式。它直接指定一个类型(通常是一个Java Bean的全限定类名),MyBatis会按照默认规则将查询结果中的列名自动映射到Java对象具有相同名称的属性上。

准备sql表

两张表,部门表和员工表,字段如下:

类型

备注

id

int

主键

name

vachar

部门名称

类型

备注

id

int

主键

name

vachar

员工姓名

gender

vachar

性别

salary

double

薪资

join_date

date

入职日期

dept_id

int

外键

bean

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

    private List<Emp> empList;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
    private Integer id;
    private String name;
    private String gender;
    private Double salary;
    private Date joinDate;
    private Integer deptId;

    //一对一关系
    private Dept dept;  //引入Dept类

}

多对一映射处理

场景模拟:

查询员工信息以及员工所对应的部门信息

已知员工是多,部门是一,一个员工对应多个部门,一个部门有多个员工。两种方式处理映射关系

1、级联方式处理映射关系

级联方式:

<!--多对一映射关系,,级联关系查询-->
   <resultMap id="empDeptMap" type="emp">
       <id column="id" property="id"></id>
       <result column="name" property="name"></result>
       <result column="gender" property="gender"></result>
       <result column="salary" property="salary"></result>
       <result column="join_date" property="joinDate"></result>
       <result column="dept_id" property="deptId"></result>
       <result column="dept_id" property="dept.id"></result>
       <result column="dname" property="dept.name"></result>
		</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid); EmpMapper接口中代码-->
   <select id="getEmpAndDeptByEid" resultMap="empDeptMap">
       select e.*,d.name as dname from emp e left join dept d on e.dept_id = d.id where e.id = #{eid}
		</select>

2、使用association处理映射关系

<!--定义一个resultMap标签,将Emp字段映射,后面就不用重复去写,需要用到直接继承extends标签即可以-->
<resultMap id="baseMap" type="emp">
    <id column="id" property="id"></id>
    <result column="name" property="name"></result>
    <result column="gender" property="gender"></result>
    <result column="salary" property="salary"></result>
    <result column="join_date" property="joinDate"></result>
    <result column="dept_id" property="deptId"></result>
</resultMap>

<resultMap id="empDeptMap" type="emp" extends="baseMap">
      <association property="dept" javaType="dept">
          <id column="id" property="id"></id>
          <result column="name" property="name"></result>
      </association>
</resultMap>
<select id="getEmpAndDeptByEid" resultMap="empDeptMap">
    select e.*,d.name as dname from emp e left join dept d on e.dept_id = d.id where e.id = #{eid}
</select>

3、分步查询

①查询员工信息

EmpMapper接口

/**
 *通过分步查询查询员工信息
 *@param eid
 *@return
 */
Emp getEmpByStep(@Param("eid") int eid);

EmpMapper.xml

分步查询中的association标签用到select属性,就是在调用下一步查询中DeptMapper接口中的一个方法;column属性即是传入的字段。比如根据员工查询部门,我们就得传入员工信息中的部门id--dept_id。

<!--   多对一 分步查询  查询员工信息--> 
  <resultMap id="empDeptStepMap" type="emp" extends="baseMap">
    
      <association property="dept"
                   select="com.softeem.mapper.DeptMapper.getEmpDeptByStep" column="dept_id">  <!--column一定必须传入的是数据库表的字段名根据什么查就传入什么字段-->
          <!--select:是在调用某个mapper对象中的某个方法,调用的一定是查询方法-->
      </association>
  </resultMap>
  <select id="getEmpByStep" resultMap="empDeptStepMap">
      select * from emp where id = #{eid}
  </select>

②根据员工所对应的部门id查询部门信息

DeptMapper接口中方法。

/**
*分步查询的第二步: 根据员工所对应的did查询部门信息
*@param did
*@return
*/
Dept getEmpDeptByStep(@Param("did") int did);

DeptMapper.xml

<!--Dept getEmpDeptByStep(@Param("did") int did);-->
<select id="getEmpDeptByStep" resultType="Dept"> 
  select * from dept where did = #{did}
</select>

一对多映射处理

场景模拟:

根据部门id查询部门以及部门中的员工信息

一对多查询时,一那方实体类就要再定义一个集合属性。即部门实体类中还应该再定义List<Emp>。因为查询一个部门,但部门内有多个员工。代码如下:

Dept实体类:

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

    private List<Emp> empList;
}

1、collenction

DeptMapper接口中定义方法:

/**
*根据部门id查询部门以及部门中的员工信息
*@param did
*@return
*/
Dept getDeptEmpByDid(@Param("did") int did);

DeptMapper.xml映射文件中代码:

<!--    根据部门id查新部门以及部门中的员工信息  注意点:一对多,在少的bean类写上多的对象集合
        在resultMap标签中写上collection标签将多的字段写上,如下,,,值得特别关注的是如果字段名重复记得给别名,否则对应不起来将报错-->
    <resultMap id="DeptEmpMap" type="dept">
        <id property="id" column="did"></id>
        <result property="name" column="dname" ></result>

                    <!--resultMap标签将EmpMapper.xml中的baseMap标签继承来,就不用再写字段的映射那么些代码了        -->
        <collection property="empList" ofType="emp"
                    resultMap="com.softeem.mapper.EmpMapper.baseMap">

        </collection>
    </resultMap>
<!--    有重复的一定要写别名-->
    <select id="getDeptEmpByDid" resultMap="DeptEmpMap">
        select e.*, d.id as did, d.name as dname from emp e, dept d where e.dept_id=d.id and d.id=#{did}
    </select>

注意:两表联查时容易出现表中字段相同的情况,这种情况一定要写别名,并且在resultMap标签中映射

2、分步查询

与上述多对一基本是一致的,只是标签不同,多对一使用的是collection标签

①查询部门信息

DeptMapper接口中方法:

/**
*分步查询部门和部门中的员工
*@param did
*@return
*/
Dept getDeptByStep(@Param("did") int did);

DeptMapper.xml文件中代码:

<!--    一对多映射处理 分步查询 -->
    <resultMap id="DeptEmpStep" type="dept">
      	<id property="id" column="id"></id>
        <result property="name" column="name" ></result>
      
        <collection property="empList"
                    select="com.softeem.mapper.EmpMapper.getEmpListByDid" column="id">

        </collection>
    </resultMap>
    <select id="getDeptByStep" resultMap="DeptEmpStep">
        select * from dept where id=#{did}
    </select>

②根据部门id查询部门中的所有员工

EmpMapper接口中定义方法:

List<Emp> getEmpListByDid(int did);

EmpMapper.xml文件中代码:

<!--List<Emp> getEmpListByDid(@Param("did") int did);-->
<select id="getEmpListByDid" resultType="Emp"> 
  select * from t_emp where did = #{did}
</select>

association和 collection

在MyBatis中,association 和 collection 是用于处理对象关联关系的标签,它们分别用于实现一对一和一对多(或多对一)的数据映射。

association (一对一或多对一映射)

  • 作用:用于描述一个复杂的属性(通常是一个对象),该属性与当前实体类之间是一对一或多对一的关系。

collection (一对多或多对多映射)

  • 作用:用于描述一个复杂属性(通常是集合类型,如List、Set等),该属性包含多个与当前实体类有一对多或多对多关系的对象。

总结来说,association 主要用于一对一或者多对一关系,而 collection 适用于处理一对多或者多对多的关系。通过这两种标签,可以方便地将关联表数据映射到Java对象图中,形成一个完整的对象模型。