• MyBatis自定义映射resultMap,处理一对多,多对一


    1、自定义映射resultMap

    复习:查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射 关系

    resultType:自动映射,用于属性名和表中字段名一致的情况 (或设置了下划线映射为驼峰)。

    resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况

    1.1、resultMap处理字段和属性的映射关系

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

    (补充:当字段名和属性名一样时,字段和属性是一 一对应的,jdbc会通过反射实现这种对应,所以,能查到完整的对象。当不一样时,又没有自己处理,那字段和属性就对应不上,查出来的对象属性全是null)

    1. <resultMap id="userResultMap" type="User">
    2. <id property="userId" column="userid">id>
    3. <result property="userName" column="user_name">result>
    4. <result property="password" column="password">result>
    5. <result property="age" column="age">result>
    6. <result property="sex" column="sex">result>
    7. resultMap>
    8. <select id="testMohu" resultMap="userResultMap">
    9. select id,user_name,password,age,sex from t_user where user_name like concat('%',#{mohu},'%')
    10. select>

    若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则,实体类中的属性 名符合Java的规则, 此时也可通过以下3种方式处理字段名和实体类中的属性的映射关系

    a>可以通过为字段起别名的方式,保证和实体类中的属性名保持一致

    b>可以在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase,可 以在查询表中数据时,自动将_类型的字段名转换为驼峰 (推荐)

    例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为 userName

    c> 使用resultMap

    1.2、多对一映射处理(对象属性)

    场景模拟:

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

    员工表和部门表的关系是多对一

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

    多对一映射:多位员工Emp对应一个部门Dept

    1. public class Emp {
    2. private Integer empId;
    3. private String empName;
    4. private Integer age;
    5. private String gender;
    6. //查询员工对应的部门信息时,必须要在Emp类中写一个Dept属性。且提供 get、set,构造器不用加上dept
    7. // 表与表有关系,在数据库中,员工表里有部门id字段。
    8. //表与表之间的关系体现在java中,就是在类中加入对象属性。因为员工和部门是多对一的关系,所以,在员工类中
    9. // 加一个Dept类型的属性。
    10. //补充:若是一对多,那要在少的一方加一个集合,比如,在Dept里里加一个List类型的属性.
    11. ///根据需求判断 只在一方加,还是两方都加。
    12. private Dept dept;//这就是所谓的 对象属性
    13. public Emp() {
    14. }
    15. public Emp(Integer empId, String empName, Integer age, String gender) {
    16. this.empId = empId;
    17. this.empName = empName;
    18. this.age = age;
    19. this.gender = gender;
    20. }
    21. 。。。。。。
    22. //提供所有属性的get、set方法,重写toString
    23. }
    1. public class Dept {
    2. private Integer deptId;
    3. private String depName;
    4. public Dept() {
    5. }
    6. public Dept(Integer deptId, String depName) {
    7. this.deptId = deptId;
    8. this.depName = depName;
    9. }
    10. 。。。。。。。。。。。。。。。。。。。。。。。
    11. //提供所有属性的get、set方法,重写toString
    12. }

    Mapper接口:

    1. public interface EmpMapper {
    2. /**
    3. * 查询指定员工的信息以及他所在部门的信息
    4. * @param empId
    5. * @return
    6. */
    7. Emp getEmpAndDeptByEid(@Param("empId") int empId);
    8. }

    想明白字段该和哪个属性进行映射

    因为dept是Emp类里的对象属性,所以,字段dept_name 对应 dept.depName

    1. <resultMap id="empDeptMap" type="Emp">
    2. <id column="emp_id" property="empId">id>
    3. <result column="emp_name" property="empName">result>
    4. <result column="age" property="age">result>
    5. <result column="gender" property="gender">result>
    6. <result column="dept_name" property="dept.depName">result>
    7. resultMap>
    8. <select id="getEmpAndDeptByEid" resultMap="empDeptMap">
    9. SELECT t_emp.*, t_dept.dept_name
    10. FROM t_emp NATURAL JOIN t_dept
    11. WHERE t_emp.emp_id=#{empId}
    12. select>

    根据自己具体业务需求写SQL语句,有时候可能写成外连接。

    1.2.2、使用association处理映射关系(推荐)

    同上。需要先在java类Emp中添加一个属性private Dept dept ;并提供get、set方法,构造器不用加上dept。重写toString。

    association标签:处理多对一的映射关系(处理实体类类型的属性)。比如Employee类中有一个Department属性

    用上这个标签更好理解,阅读也方便。我个人比较喜欢这种方式。

    将映射文件写成下面这样:

    1. <resultMap id="empDeptMap" type="Emp">
    2. <id column="emp_id" property="empId">id>
    3. <result column="emp_name" property="empName">result>
    4. <result column="age" property="age">result>
    5. <result column="gender" property="gender">result>
    6. <association property="dept" javaType="Dept">
    7. <id column="dept_id" property="deptId">id>
    8. <result column="dept_name" property="deptName">result>
    9. association>
    10. resultMap>
    11. <select id="getEmpAndDeptByEid" resultMap="empDeptMap">
    12. SELECT t_emp.*, t_dept.*
    13. FROM t_emp NATURAL JOIN t_dept
    14. WHERE t_emp.emp_id=#{empId}
    15. select>
    1. @Test
    2. public void testEmpDept(){
    3. SqlSession sqlSession = sqlSessionUtils.getSqlSession();
    4. EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    5. Emp empAndDeptByEid = mapper.getEmpAndDeptByEid(1);
    6. System.out.println(empAndDeptByEid);
    7. //Emp{empId=1, empName='赵四', age=20, gender='男', dept=Dept{deptId=1, depName='a部门'}}
    8. }
    1.2.3、分步查询

    文字记录不太清楚

    去看尚硅谷杨博超老师的SSM视频。或其他学习资源

    1.3、一对多映射处理( 集合属性)

    多对一反过来就是一对多,一个部门对应多个员工。需要在部门类中加一个List emps属性,提供get、set方法,toString。 构造器中不用加List emps处理一对多的映射关系:

    • 方式一:collection

    • 方式二:分步查询

    1. public class Dept {
    2. private Integer deptId;
    3. private String deptName;
    4. //一对多,一个部门里有多个员工
    5. private List emps;
    6. ..........
    7. }

    需求:根据部门id查询部门以及该部门中所有员工的信息

    1.3.1、collection

    根据具体业务需要写sql语句,看是否需要使用左外连接或右外连接. 例如下面的左外连接,因为有的人没有部门,但是又想查所有人。

    1. SELECT *
    2. FROM t_dept
    3. LEFT JOIN t_emp ON t_dept.dept_id = t_emp.dept_id
    4. WHERE t_dept.dept_id=#{deptId}
    5. * 表示查询2表的所有字段

    我的例子用的是自然连接:

    1. SELECT * # 两个表的所有字段
    2. FROM t_dept
    3. NATURAL JOIN t_emp WHERE t_dept.dept_id=#{deptId}
    1. DeptMapper接口里:
    2. /**
    3. * 根据部门id查新部门以及该部门中的员工信息
    4. * @param did
    5. * @return
    6. */
    7. Dept getDeptAndEmpByDeptId(@Param("deptId") int deptId);
    1. DeptMapper.xml 里:
    2. <resultMap id="deptAndEmpResultMap" type="Dept">
    3. <id column="dept_id" property="deptId">id>
    4. <result column="dept_name" property="deptName">result>
    5. <collection property="emps" ofType="Emp">
    6. <id column="emp_id" property="empId">id>
    7. <result column="emp_name" property="empName">result>
    8. <result column="age" property="age">result>
    9. <result column="gender" property="gender">result>
    10. collection>
    11. resultMap>
    12. <select id="getDeptAndEmpByDeptId" resultMap="deptAndEmpResultMap">
    13. SELECT t_dept.*,t_emp.*
    14. FROM t_dept
    15. NATURAL JOIN t_emp WHERE t_dept.dept_id=#{deptId}
    16. select>
    1. @Test
    2. public void testGetDeptAndEmpByDeptId(){
    3. SqlSession sqlSession = sqlSessionUtils.getSqlSession();
    4. DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
    5. Dept deptAndEmpByDeptId = mapper.getDeptAndEmpByDeptId(1);
    6. System.out.println(deptAndEmpByDeptId);
    7. }
    8. DEBUG 09-16 19:51:25,389 ==> Preparing: SELECT t_dept.*,t_emp.* FROM t_dept NATURAL JOIN t_emp WHERE t_dept.dept_id=? (BaseJdbcLogger.java:137)
    9. DEBUG 09-16 19:51:25,421 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:137)
    10. DEBUG 09-16 19:51:25,455 <== Total: 2 (BaseJdbcLogger.java:137)
    11. Dept{deptId=1, deptName='a部门',
    12. emps=[
    13. Emp{empId=1, empName='aaaa', age=20, gender='男', dept=null},
    14. Emp{empId=2, empName='bbbb', age=23, gender='男', dept=null}
    15. ]
    16. }

    个人理解:

    association 是“关系,关联”的意思,专门用来 负责属性为实体类对象(非List集合)时的映射规则,

    collection 是“集合”的意思,专门用来负责属性为List 时的映射规则。

    所以,association负责“多对一”,collection负责”一对多“

    1.3.2、分步查询

    去看尚硅谷杨博超老师的SSM视频。或其他学习资源

  • 相关阅读:
    Redis 的特点及命令大全
    报错!Jupyter notebook 500 : Internal Server Error
    【抓包分析】通过ChatGPT解密还原某软件登录算法实现绕过手机验证码登录
    小胶质细胞仅仅是神经系统内的“配角”?
    JavaParse入门
    python爬取公众号之 创建个人微信公众号
    14.4 Socket 双向数据通信
    C++图书资源管理系统
    如果再爱一次 你还会选我吗
    SaaSBase:什么是SaleSmartly?
  • 原文地址:https://blog.csdn.net/weixin_60664694/article/details/133822213