SSM项目从零开始到入门025-mybatis的resultMap自定义高级映射规则

       通过前面的了解,我们指定查询结果的返回值类型都是通过使用select元素的resultType属性来指定,来让MyBatis自动将查询结果集封装成我们希望的类型进行返回。
     resultType属性非常有用,但在返回结果类型比较复杂的情况下却无能为力,为此,MyBatis在select元素中还为我们提供了另外一个resultMap属性,用于引用一个使用<resultMap/>元素定义好的自定义结果集映射规则。

    <resultMap/>算是MyBatis中最重要、最强大的元素了,它可以让你比使用JDBC调用结果集省掉90%的代码,也可以让你做许多JDBC不支持的事。 事实上,编写类似的对复杂语句联合映射的代码也许会需要上千行。resultMap的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们的关系。

resultMap子元素:

<!---用来将查询结果作为参数注入到实例的构造方法中->
<constructor>    
   <!--标记结果作为 ID-->
   <idArg />     
   <!--标记结果作为普通参数-->
   <arg />        
</constructor>  
<!--一个ID结果,标记结果作为 ID-->
<id/>         
<!--一个普通结果,JavaBean的普通属性或字段-->
<result/>      
<!--关联其他的对象-->
<association></association>     
<!--关联其他的对象集合--> 
<collection></collection>       
<!--鉴别器,根据结果值进行判断,决定如何映射-->   
<discriminator>             
    <!--结果值的一种情况,将对应一种映射规则-->
    <case></case>    
</discriminator>
     在一个<resultMap/>元素中,这些子元素出现的先后顺序是有严格规定的,它们从前到后依次是:constructor-->id --> result--> association-->collection -->discriminator。
id & result

     <id/>和<result/>是resultMap中最基本的映射内容,它们都可以将查询结果中一个单独列的值映射为返回结果对象中的简单数据类型(字符串,整型,双精度浮点数,日期等)的单独属性或字段。这两者之间的唯一不同是id 表示的结果将是当比较对象实例时用到的标识属性。这帮助来改进整体表现,特别是缓存和嵌入结果映射(也就是联合映射) 。

     

<!-- 返回javaBean对象 -->  
<resultMap type="User" id="userResultMap">  
    <id column="USER_ID" property="userId" />  
    <result column="USER_NAME" property="userName" />  
    <result column="USER_PASS" property="passWord" />  
    <result column="USER_GENDER" property="gender" />   
</resultMap>
<!-- 返回Map对象 -->  
<resultMap type="map" id="userResultMap">  
    <id column="USER_ID" property="userId" javaType="long"/>  
    <result column="USER_NAME" property="userName" javaType="string"/>  
    <result column="USER_PASS" property="passWord" javaType="string"/>  
    <result column="USER_GENDER" property="gender" javaType="string"/>  
</resultMap>

<id/>和<result/>都支持以下几个属性:

属性描述
column从数据库中查询到的结果集的列名或列别名
property将 column属性指定的列结果映射到对象的哪个属性
javaType列结果在对象中所对应的Java数据类型,返回类型为Map时需指定
jdbcType列结果在数据库中所支持的JDBC 类型
typeHandler所使用的类型处理器

为了未来的参考,MyBatis 通过包含的 jdbcType 枚举型,支持下面的 JDBC 类型。

BITFLOATCHARTIMESTAMPOTHERUNDEFINED
TINYINTREALVARCHARBINARYBLOBNVARCHAR
SMALLINTDOUBLELONGVARCHARVARBINARYCLOBNCHAR
INTEGERNUMERICDATELONGVARBINARYBOOLEANNCLOB
BIGINTDECIMALTIMENULLCURSORARRAY

constructor

       使用<constructor/>元素可以在对象实例化时,将查询到结果集作为参数注入到实例的构造方法中,以实现对实例化对象的特殊处理。
      例如,为了防止由于数据库user表中的年龄字段长期未更新,而导致查询出来的年龄信息不准确,我们希望查询user信息时根据用户的生日计算出用户的年龄,而不再直接从数据库中获取用户的年龄信息。
首先在用户实体类User.java中增加如下构造方法:
     
private static final SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");  
public User(Long userId, Date birthday) {  
    super();  
    this.userId = userId;  
    if (null != birthday) { 
        this.birthday = birthday;  
        int startYear = Integer.parseInt(yearFormat.format(birthday));  
        int nowYear = Integer.parseInt(yearFormat.format(new Date()));  
        this.age = nowYear - startYear;  
    }  
}  

相应的Mapper配置如下:

<resultMap type="User" id="userResultMap">  
    <constructor>  
        <idArg column="USER_ID" javaType="java.lang.Long" />  
        <arg column="USER_BIRTHDAY" javaType="java.util.Date" />  
    </constructor>  
    <id column="USER_ID" property="userId" />  
    <result column="USER_NAME" property="userName" />  
    <result column="PASS_WORD" property="userGender" />  
</resultMap>  
<select id="selectUserById" resultMap="userResultMap">  
    select * from  t_user where  USER_ID =  #{userId}  
</select>  
     <constructor/>元素的<idArg/>和<arg/>除了支持示例中的column和javaType属性,还支持以下几个属性:jdbcType、typeHandler、select、resultMap、name,其中的name属性从3.4.3版本起开始引入,用来指定该在构造方法中形参的名字。

注意:使用<constructor/>元素在构造方法中初始化的参数若使用resultMap的其他子元素进行映射,则构造方法为对象实例赋予的属性值将被覆盖。

association

<association/>元素用于处理查询结果中关联其他对象的情况。

比如:一个用户属于一个部门,我们在查询一个用户的信息时,想要把他所在的部门也一并查出。

public class User{  
  
    private Long userId;       //用户id
    private String userName;   //用户名称
    ....                       //省略一些属性
    private Dept dept;         //所属部门
      
    //此处省略get和set方法  
  
}

MyBatis提供了两种不同的方式用来处理这种对象关联查询:嵌套查询和嵌套结果。


嵌套查询

所谓嵌套查询,指的是通过执行另外一个 SQL 映射语句来返回所关联的对象类型。

<association/>元素可以通过columnPrefix属性可以去除查询结果内列名的指定前缀。

<resultMap type="User" id="userResultMap">  
    <id column="USER_ID" property="userId" />  
    <result column="USER_NAME" property="userName" />  
    <association column="DEPT_ID" property="dept" select="selectDeptById" javaType="Dept" />  
</resultMap>  
<select id="selectUserById" resultMap="userResultMap">  
    select * from  t_user where  USER_ID =  #{userId}  
</select>  
<resultMap type="Dept" id="deptResultMap">  
    <id column="DEPT_ID" property="deptId" />  
    <result column="DEPT_NAME" property="deptName" />  
</resultMap>  
<select id="selectDeptById" resultMap="deptResultMap">  
    select * from  t_dept  where  DEPT_ID =  #{deptId}  
</select>
嵌套结果

所谓嵌套结果,指的是通过联表查询将所需的所有字段内容先查询出来,再通过级联属性映射来创建复杂类型的结果对象。


<resultMap type="User" id="userResultMap">  
    <id column="USER_ID" property="userId" />  
    <result column="USER_NAME" property="userName" />  
    <result column="DEPT_ID" property="dept.deptId" />  
    <result column="DEPT_NAME" property="dept.deptName" />  
</resultMap>  
<sql id="userAndDeptFields">  
    u.USER_ID   AS USER_ID,  
    u.USER_NAME AS USER_NAME,  
    d.DEPT_ID   AS DEPT_ID,  
    d.DEPT_NAME AS DEPT_NAME  
</sql>  
<select id="selectUserById" resultMap="userResultMap">  
    SELECT  
    <include refid="userAndDeptFields"></include>  
    FROM  t_user u  LEFT OUTER JOIN  t_dept d  ON u.DEPT_ID = d.DEPT_ID  
    WHERE  
    u.USER_ID = #{userId}  
</select> 

此时的resultMap还可以写为如下两种形式。

<resultMap type="User" id="userResultMap">  
    <id column="USER_ID" property="userId" />  
    <result column="USER_NAME" property="userName" />  
    <association property="dept" javaType="Dept">  
        <id column="DEPT_ID" property="deptId" />  
        <result column="DEPT_NAME" property="deptName" />  
    </association>  
</resultMap> 
<resultMap type="User" id="userResultMap">  
    <id column="USER_ID" property="userId" />  
    <result column="USER_NAME" property="userName" />  
    <association property="dept" resultMap="deptResultMap">  </association>  
</resultMap>  
<resultMap type="Dept" id="deptResultMap">  
    <id column="DEPT_ID" property="deptId" />  
    <result column="DEPT_NAME" property="deptName" />  
</resultMap> 

collection

<collection/>元素用于处理查询结果中关联其他对象集合的情况,比如:一个部门包含多个员工,我们在查询一个部门的信息时,想要把这个部门里的员工集合也一并查出。

部门实体:

public class Dept{  
    private Long deptId;       //部门id
    private String deptName;   //部门名称
    ...
    private List<User> users;  //部门下用户集合
    //此处省略get和set方法  
}  

嵌套查询

    <resultMap type="Dept" id="deptResultMap">  
        <id column="DEPT_ID" property="deptId" />  
        <result column="DEPT_NAME" property="deptName" />  
        <collection column="DEPT_ID" property="users" javaType="list"  select="userListByClass">  </collection>  
    </resultMap>  
  
    <resultMap type="User" id="userResultMap">  
        <id column="USER_ID" property="userId" />  
        <result column="USER_NAME" property="userName" />  
    </resultMap>  
  
    <select id="selectDeptById" resultMap="deptResultMap">  
        select * from  t_dept  where DEPT_ID =  #{deptId}  
    </select>  
  
    <select id="userListByClass" parameterType="long"  resultMap="userResultMap">  
        select * from  t_user   where   DEPT_ID = #{userId}  
    </select>

嵌套结果

<resultMap type="Dept" id="deptResultMap">  
    <id column="DEPT_ID" property="deptId" />  
    <result column="DEPT_NAME" property="deptName" />  
    <collection column="DEPT_ID" property="users" javaType="list"  ofType="User">  
        <id column="User_ID" property="userId" />  
        <result column="USER_NAME" property="userName" />  
    </collection>  
</resultMap>  
<sql id="deptAndUsersFields">  
    d.DEPT_ID   AS DEPT_ID,  
    d.DEPT_NAME AS DEPT_NAME,  
    u.USER_ID   AS USER_ID,  
    u.USER_NAME AS USER_NAME  
</sql>  
<select id="selectDeptById" parameterType="long" resultMap="deptResultMap">  
    SELECT  
    <include refid="deptAndUsersFields"></include>  
    FROM  t_dept d LEFT JOIN t_user u ON d.DEPT_ID = u.DEPT_ID  
    WHERE  
    d.DEPT_ID = #{deptId}  
</select> 

此时的resultMap也可以写为如下形式。

<resultMap type="Dept" id="deptResultMap">  
    <id column="DEPT_ID" property="deptId" />  
    <result column="DEPT_NAME" property="deptName" />  
    <collection property="users" javaType="list" ofType="User" resultMap="userResultMap">  </collection>  
</resultMap>  
<resultMap type="User" id="userResultMap">  
    <id column="USER_ID" property="userId" />  
    <result column="USER_NAME" property="userName" />  
</resultMap> 

discriminator

<discriminator/>元素很像Java语言中的switch 语句,允许用户根据查询结果中指定字段的不同取值来执行不同的映射规则,比如:在查询一个部门的员工信息时,如果员工是性别为男则将其年龄信息一并查出,如果学生为女性则不查询其年龄信息而是将部门信息一并查出。

<resultMap type="User" id="usersResultMap">  
    <discriminator column="USER_GENDER" javaType="string">  
        <case value="男" resultMap="maleResultMap"/>  
        <case value="女" resultMap="femaleResultMap"/>  
    </discriminator>  
</resultMap>  
<resultMap type="User" id="maleResultMap">  
    <id column="USER_ID" property="userId" />  
    <result column="USER_NAME" property="userName" />  
    <result column="USER_AGE" property="userAge" />  
</resultMap>  
<resultMap type="User" id="femaleResultMap">  
    <id column="USER_ID" property="userId" />  
    <result column="USER_NAME" property="userName" />  
    <association column="DEPT_ID" property="dept"  javaType="Dept">  
        <id column="DEPT_ID" property="deptId" />  
        <result column="DEPT_NAME" property="deptName" />  
    </association>  
</resultMap> 

此时的resultMap也可以写为如下形式。

<resultMap type="User" id="usersResultMap">  
    <id column="USER_ID" property="userId" />  
    <result column="USER_NAME" property="userName" />  
    <discriminator column="USER_GENDER" javaType="string">  
        <case value="男" resultType="User">  
            <result column="USER_AGE" property="userAge" />  
        </case>  
        <case value="女" resultType="User">  
            <association column="DEPT_ID" property="userDept"  javaType="Dept">  
                <id column="DEPT_ID" property="deptId" />  
                <result column="DEPT_NAME" property="deptName" />  
            </association>  
        </case>  
    </discriminator>  
</resultMap>  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心歌技术

打赏不能超过你的早餐钱!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值