在使用MyBatis作为ORM框架时,我们经常遇到各种数据映射问题,特别是处理复杂的数据关系,如多对一关系。在本文中,我们将深入探讨如何使用 MyBatis 的 ResultMap
来自定义映射,以员工与其所属部门之间的多对一关系,优雅地处理多对一关系的映射。
实体类设计
首先,我们有一个Emp类,代表员工,其中包含一个Dept对象,代表员工所属的部门。
public class Emp {
private Integer eid;
private String empName;
private Integer age;
private String sex;
private String email;
private Dept dept;
// 省略构造器、getter和setter方法
}
在MyBatis中,处理这种多对一关系主要有两种方式:级联方式 和 association标签方式。
一、级联方式
级联方式是通过直接在 resultMap
中指定员工和部门属性的对应关系来实现的。这种方式简单直观,但可能会显得有点冗长。
<resultMap id="empAndDeptResultMapOne" type="Emp">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<result property="email" column="email"/>
<result property="dept.did" column="did"/>
<result property="dept.deptName" column="dept_name"/>
</resultMap>
对应的SQL查询使用了 LEFT JOIN 来连接员工和部门表:
<select id="getEmpAndDept" resultMap="empAndDeptResultMapOne">
select * from t_emp
left join t_dept on t_emp.dept_id = t_dept.did
where t_emp.eid = #{eid}
</select>
注意:这里假设 t_emp
表中有一个 dept_id
字段用于与 t_dept
表的 did
字段关联。
二、使用 association 标签
association
标签是 MyBatis 中专门用于处理多对一和一对一关系的。这种方式使映射关系更加清晰,特别是当关联对象有多个属性时。
<resultMap id="empAndDeptResultMapTwo" type="Emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<association property="dept" javaType="Dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
</association>
</resultMap>
<!--Emp getEmpAndDept(@Param("eid")Integer eid);-->
<select id="getEmpAndDept" resultMap="empAndDeptResultMapTwo">
select * from t_emp
left join t_dept on t_emp.eid = t_dept.did
where t_emp.eid = #{eid}
</select>
说明:
association
:处理多对一的映射关系property
:需要处理多对一的映射关系的属性名javaType
:该属性的类型
SQL查询与级联方式相同。
三、分步查询
除了上述两种通过 JOIN 来一次性获取所有数据的方式外,MyBatis还支持**分步查询。**首先查询员工信息,然后根据员工信息中的部门ID去查询部门信息。
在 association
标签中,可以使用 select
属性来指定另一个查询的ID,用于获取关联的对象。例如:
- 首先查询员工信息
//EmpMapper里的方法
/**
* 通过分步查询,员工及所对应的部门信息
* 分步查询第一步:查询员工信息
* @param
* @return com.example.mybatis.pojo.Emp
*/
Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);
<resultMap id="empAndDeptByStepResultMap" type="Emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<association property="dept" select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo" column="did">
</association>
</resultMap>
<!--Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);-->
<select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
select * from t_emp where eid = #{eid}
</select>
- 再查询部门信息
//DeptMapper里的方法
/**
* 通过分步查询,员工及所对应的部门信息
* 分步查询第二步:通过did查询员工对应的部门信息
* @param
* @return com.exapmle.mybatis.pojo.Emp
*/
Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);
<!--此处的resultMap仅是处理字段和属性的映射关系-->
<resultMap id="EmpAndDeptByStepTwoResultMap" type="Dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
</resultMap>
<!--Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);-->
<select id="getEmpAndDeptByStepTwo" resultMap="EmpAndDeptByStepTwoResultMap">
select * from t_dept where did = #{did}
</select>
在分步查询中,getEmpAndDeptByStepTwo是一个单独的查询,它根据部门ID返回部门信息。这种方式可以减少初始查询的复杂度,但可能会增加数据库访问次数。
说明:
-
select
:设置分布查询的 sql 的唯一标识(namespace.SQLId
或 mapper 接口的全类名.方法名) -
column
:设置分步查询的条件
总结
处理多对一关系是ORM框架中的常见需求。在MyBatis中,你可以通过级联方式、association标签或分步查询来优雅地实现这一需求。选择哪种方式取决于你的具体需求和数据库性能考虑。