08、自定义映射ResultMap
8.1、解决字段名与属性名的映射关系
问题:表中的字段名与实体类中的属性名不一致。
【EmpMapper.java】
/**
* 查询所有员工信息
*/
List<Emp> getAllEmp();
【EmpMapper.xml】
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultType="emp">
select * from t_emp
</select>
【EmpMapperTest.java】
@Test
public void getAllEmp() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
List<Emp> list = empMapper.getAllEmp();
list.forEach(emp -> {
System.out.println(emp);
});
}
运行结果:
Emp{eid=1, empName=‘null’, age=21, sex=‘男’, email=‘zhangsan@123.com’}
Emp{eid=2, empName=‘null’, age=20, sex=‘女’, email=‘lisi@123.com’}
Emp{eid=3, empName=‘null’, age=24, sex=‘男’, email=‘wangwu@123.com’}
Emp{eid=4, empName=‘null’, age=22, sex=‘男’, email=‘zhaoliu@123.com’}
Emp{eid=5, empName=‘null’, age=25, sex=‘女’, email=‘tianqi@123.com’}bug:
empName的值均为空
分析:
empName与数据库表中的emp_Name不一致,无法匹配映射。
若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性 名符合Java的规则(使用驼峰)。
解决字段名和属性名不一致的情况:
- 为字段起别名,保持和属性名的一致
- 设置全局配置,将
_
自动映射为驼峰 - 通过
ResultMap
设置自定义的映射关系
8.1.1、使用字段别名
为字段起别名,保持和属性名的一致
【EmpMapper.xml】
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultType="emp">
select eid,emp_name empName,age,sex,email from t_emp
</select>
运行结果:
Emp{eid=1, empName=‘张三’, age=21, sex=‘男’, email=‘zhangsan@123.com’}
Emp{eid=2, empName=‘李四’, age=20, sex=‘女’, email=‘lisi@123.com’}
Emp{eid=3, empName=‘王五’, age=24, sex=‘男’, email=‘wangwu@123.com’}
Emp{eid=4, empName=‘赵六’, age=22, sex=‘男’, email=‘zhaoliu@123.com’}
Emp{eid=5, empName=‘田七’, age=25, sex=‘女’, email=‘tianqi@123.com’}
8.1.2、使用全局配置mapUnderscoreToCamelCase
- 可以在
MyBatis
的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase
,可 以在查询表中数据时,自动将_类型的字段名转换为驼峰 - 例如:字段名
user_name
,设置了mapUnderscoreToCamelCase
,此时字段名就会转换为userName
【mybatis_config.xml】
<!--设置MyBatis的全局配置-->
<settings>
<!--将_自动映射为驼峰,emp_name:empName-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
【EmpMapper.xml】
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultType="emp">
<!--select eid,emp_name empName,age,sex,email from t_emp-->
select * from t_emp
</select>
8.1.3、使用ResultMap
若字段名和实体类中的属性名不一致,则可以通过resultMap
设置自定义映射
【EmpMapper.xml】
<!--
resultMap:设置自定义映射关系
id:唯一标识,不能重复
type:设置映射关系中的实体类类型
子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
属性:
property:设置映射关系中的属性名,必须是type属性所设置的实体类类型中的属性名
column:设置映射关系中的字段名,必须是sql语句查询的字段名
-->
<resultMap id="empResultMap" 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>
</resultMap>
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultMap="empResultMap">
select * from t_emp
</select>
8.2、解决多对一的映射关系
问题:Emp和Dept为多对一的映射关系
解决多对一的映射关系的情况:
- 级联属性赋值
- 使用
association
- 分步查询
8.2.1、级联属性赋值
【EmpMapper.xml】
<!--处理多对一映射关系方式一:级联属性赋值-->
<resultMap id="empAndDeptResultMapOne" 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>
<result property="dept.did" column="did"></result>
<result property="dept.deptName" column="dept_name"></result>
</resultMap>
<!--Emp getEmpAndDept(@Param("eid") Integer eid);-->
<select id="getEmpAndDept" resultMap="empAndDeptResultMapOne">
select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
</select>
运行结果:
Emp{eid=1, empName=‘张三’, age=21, sex=‘男’, email=‘zhangsan@123.com’, dept=Dept{did=1, deptName=‘A’}}
8.2.2、使用association
【EmpMapper.xml】
<!--处理多对一映射关系方式二:association-->
<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:需要处理的多对一的映射关系的属性名
javaType:该属性的类型
-->
<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.did = t_dept.did where t_emp.eid = #{eid}
</select>
8.2.3、分步查询
8.2.3.1、分步查询
- 第一步:查询员工信息
【EmpMapper.java】
/**
* 通过分步查询查询员工以及员工所对应的部门信息
* 分步查询第一步:查询员工信息
*/
Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);
【EmpMapper.xml】
<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>
<!--
select:设置分步查询的SQL的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
column:将sql以及查询结果中的某个字段设置为分步查询的条件
-->
<association property="dept"
select="com.ssm.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>
- 第二步:通过did查询员工所对应的部门信息
【DeptMapper.java】
/**
* 通过分步查询查询员工以及员工所对应的部门信息
* 分步查询第二步:通过did查询员工所对应的部门信息
*/
Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);
【DeptMapper.xml】
<!--Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);-->
<select id="getEmpAndDeptByStepTwo" resultType="dept">
select * from t_dept where did = #{did}
</select>
8.2.3.2、延迟加载
1、分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled
:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载aggressiveLazyLoading
:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载
2、此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql
。此时可通过association
和 collection
中的fetchType
属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加载)|eager(立即加载)”
3、代码演示:
(1)配置核心配置文件
【mybatis-config.xml】
<!--设置MyBatis的全局配置-->
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
(2)通过fetchType
设置是否开启延迟加载
【EmpMapper.xml】
<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>
<!--
select:设置分步查询的SQL的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
column:将sql以及查询结果中的某个字段设置为分步查询的条件
fetchType:当开启了全局的延迟加载后,可通过此属性手动控制延迟加载的效果
fetchType = "lazy|eager"
lazy:表示延迟加载
eager:表示立即加载
-->
<association property="dept"
select="com.ssm.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="did"
fetchType="eager">
</association>
</resultMap>
(3)代码测试:
【EmpMapperTest.java】
@Test
public void getEmpAndDeptByStep() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpAndDeptByStepOne(1);
System.out.println(emp.getEmpName());
System.out.println("-------------------------------");
System.out.println(emp.getDept());
}
(4)运行结果:
- 未开启延迟加载
- 开启延迟加载
8.3、解决一对多的映射关系
问题:Dept和Emp为一对多的映射关系
解决一对多的映射关系的情况:
collection
- 分步查询
8.3.1、collection
【DeptMapper.java】
/**
* 获取部门以及部门中所有的员工信息
*/
Dept getDeptAndEmp(@Param("did") Integer did);
【DeptMapper.xml】
<resultMap id="deptAndEmpResultMap" type="dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
<!--
collection:处理一对多的映射关系
ofType:表示该属性所对应的集合中存储数据的类型
-->
<collection property="emps" ofType="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>
</collection>
</resultMap>
<!--Dept getDeptAndEmp(@Param("did") Integer did);-->
<select id="getDeptAndEmp" resultMap="deptAndEmpResultMap">
select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
</select>
8.3.2、分步查询
- 第一步:查询部门信息
【DeptMapper.java】
/**
* 通过分步查询查询部门以及部门中所有的员工信息
* 分步查询第一步:查询部门信息
*/
Dept getDeptAndEmpByStepOne(@Param("did") Integer did);
【DeptMapper.xml】
<resultMap id="deptAndEmpByStepResultMap" type="dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
<collection property="emps"
select="com.ssm.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
column="did"
></collection>
</resultMap>
<!--Dept getDeptAndEmpByStepOne(@Param("did") Integer did);-->
<select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpByStepResultMap">
select * from t_dept where did = #{did}
</select>
- 根据
did
查询员工信息
【EmpMapper.java】
/**
* 通过分步查询查询部门以及部门中所有的员工信息
* 分步查询第二步:根据did查询员工信息
*/
List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);
【EmpMapper.xml】
<!--List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);-->
<select id="getDeptAndEmpByStepTwo" resultType="emp">
select * from t_emp where did = #{did}
</select>