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

1、自定义映射resultMap

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

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

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

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

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

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

<!--
	select标签里的resultMap属性设置使用哪个映射规则
    resultMap标签:设置自定义映射(自定义字段和属性的映射规则)
            	属性: id:表示自定义映射的唯一标识,即给你这个具体的映射规则resultMap起一个唯一名字
                	  type:查询的数据要映射的实体类的类型
    子标签:
        id标签:设置主键的映射关系
        result标签:设置普通字段的映射关系。即你想要你的结果是怎么映射的,怎么一一对应填值的
        association标签:设置多对一的映射关系。比如Employee类中有一个Department属性
        collection标签:设置一对多的映射关系。比如Department类中有一个。List<Employee>属性
        属性:
        property:设置映射关系中实体类中的属性名,必须是java中实体类的属性名
        column:设置映射关系中的字段名.必须是sql查询出的某个字段(出现在sql查询语句的字段)
因为是自定义,所以,java中的属性名不是驼峰的也可,mysql里的属性不是_也可。
		property和column的先后位置任意
-->
<resultMap id="userResultMap" type="User">
    <id property="userId" column="userid"></id>
    <result property="userName" column="user_name"></result>
    <result property="password" column="password"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
</resultMap>
<!--List<User> testMohu(@Param("mohu") String mohu);使用刚才定义的映射规则-->
<select id="testMohu" resultMap="userResultMap">
    <!--select * from t_user where username like '%${mohu}%'-->
    select id,user_name,password,age,sex from t_user where user_name like concat('%',#{mohu},'%')
</select>

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

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

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

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

c> 使用resultMap

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

场景模拟:

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

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

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

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

public class Emp {
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;
    //查询员工对应的部门信息时,必须要在Emp类中写一个Dept属性。且提供 get、set,构造器不用加上dept
    // 表与表有关系,在数据库中,员工表里有部门id字段。
    //表与表之间的关系体现在java中,就是在类中加入对象属性。因为员工和部门是多对一的关系,所以,在员工类中
    // 加一个Dept类型的属性。  
    //补充:若是一对多,那要在少的一方加一个集合,比如,在Dept里里加一个List<Emp>类型的属性.
    ///根据需求判断 只在一方加,还是两方都加。
    private Dept dept;//这就是所谓的  对象属性
    
   public Emp() {
    }

    public Emp(Integer empId, String empName, Integer age, String gender) {
        this.empId = empId;
        this.empName = empName;
        this.age = age;
        this.gender = gender;
    }
    。。。。。。
	//提供所有属性的get、set方法,重写toString
}
public class Dept {
    private Integer deptId;
    private String depName;
    public Dept() {
    }

    public Dept(Integer deptId, String depName) {
        this.deptId = deptId;
        this.depName = depName;
    }
    。。。。。。。。。。。。。。。。。。。。。。。
    //提供所有属性的get、set方法,重写toString
}

Mapper接口:

public interface EmpMapper {
    /**
     * 查询指定员工的信息以及他所在部门的信息
     * @param empId
     * @return
     */
    Emp getEmpAndDeptByEid(@Param("empId") int empId);
}

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

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

    <resultMap id="empDeptMap" type="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>
        
        <!--这里仍然用result标签。需要部门表里的哪几些字段,这就写几个,但要保证java类中有属性,且提供了get、set方法。dept是Emp类中的属性,depName是dept对象的属性,实际调用getDeptName方法-->
        <result column="dept_name" property="dept.depName"></result>
    </resultMap>
    <!--Emp getEmpAndDeptByEid(@Param("empId") int empId);-->
    <select id="getEmpAndDeptByEid" resultMap="empDeptMap">
        SELECT t_emp.*, t_dept.dept_name
        FROM t_emp NATURAL JOIN t_dept
        WHERE t_emp.emp_id=#{empId}
    </select>

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

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

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

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

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

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

    <resultMap id="empDeptMap" type="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>
        <!--<result column="dept_name" property="dept.deptName"></result>-->
        <!--<result column="dept_id" property="dept.deptId"></result>-->
        <!--只有这发生了变化。-->
        <association property="dept" javaType="Dept">
            <!--也是需要哪些部门表中的字段,就写哪些。因为我的部门表里总共2个字段,而且查的是t_dept.*,所以,我这写了2个。 -->
            <id column="dept_id" property="deptId"></id>
            <result column="dept_name" property="deptName"></result>
      
        </association>
    </resultMap>

    <!--Emp getEmpAndDeptByEid(@Param("empId") int empId);-->
    <select id="getEmpAndDeptByEid" resultMap="empDeptMap">
        SELECT t_emp.*, t_dept.*
        FROM t_emp NATURAL JOIN t_dept
        WHERE t_emp.emp_id=#{empId}
    </select>
  @Test
    public void testEmpDept(){
        SqlSession sqlSession = sqlSessionUtils.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        Emp empAndDeptByEid = mapper.getEmpAndDeptByEid(1);
        System.out.println(empAndDeptByEid);
        //Emp{empId=1, empName='赵四', age=20, gender='男', dept=Dept{deptId=1, depName='a部门'}}

    }
1.2.3、分步查询

文字记录不太清楚

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

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

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

  • 方式一:collection

  • 方式二:分步查询

public class Dept {
    private Integer deptId;
    private String deptName;
	//一对多,一个部门里有多个员工
    private List<Emp> emps;
    ..........
}

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

1.3.1、collection

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

SELECT *
FROM t_dept
LEFT JOIN t_emp ON t_dept.dept_id = t_emp.dept_id
WHERE t_dept.dept_id=#{deptId}

* 表示查询2表的所有字段

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

SELECT *  # 两个表的所有字段
FROM t_dept
NATURAL JOIN t_emp WHERE t_dept.dept_id=#{deptId}
DeptMapper接口里:
/**
* 根据部门id查新部门以及该部门中的员工信息
* @param did
* @return
*/
  Dept getDeptAndEmpByDeptId(@Param("deptId") int deptId);
   DeptMapper.xml 里:

<resultMap id="deptAndEmpResultMap" type="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
    <!--collection标签:处理一对多的关系映射(处理属性为集合类型的)。一个Dept对象里有多个Emp对象-->
        <!--ofType属性:设置集合里面存储的数据类型是啥。存储的是Emp类型-->
        <!--因为collection标签已经说明是了处理集合的,所以不能用javaType
collection是集合的意思,List<Emp>正好是一个集合,所以用来处理一对多-->
        <collection property="emps" ofType="Emp">
            <id column="emp_id" property="empId"></id>
            <result column="emp_name" property="empName"></result>
            <result column="age" property="age"></result>
            <result column="gender" property="gender"></result>
        </collection>
    </resultMap>
    <!--Dept getDeptAndEmpByDeptId(@Param("deptId") int deptId);-->
    <select id="getDeptAndEmpByDeptId" resultMap="deptAndEmpResultMap">
        SELECT t_dept.*,t_emp.*
        FROM t_dept
                 NATURAL JOIN t_emp WHERE t_dept.dept_id=#{deptId}
    </select>
    @Test
    public void testGetDeptAndEmpByDeptId(){
        SqlSession sqlSession = sqlSessionUtils.getSqlSession();
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept deptAndEmpByDeptId = mapper.getDeptAndEmpByDeptId(1);
        System.out.println(deptAndEmpByDeptId);

    }

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) 
DEBUG 09-16 19:51:25,421 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:137) 
DEBUG 09-16 19:51:25,455 <==      Total: 2 (BaseJdbcLogger.java:137) 
    
Dept{deptId=1, deptName='a部门',
     emps=[
           Emp{empId=1, empName='aaaa', age=20, gender='男', dept=null},
           Emp{empId=2, empName='bbbb', age=23, gender='男', dept=null}
          ]
    }

个人理解:

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

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

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

1.3.2、分步查询

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值