ResultMap
resultMap元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的长达数千行的代码。ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。
一、字段映射
如果数据库中表的字段与User类的属性名称一致,我们就可以使用resultType来返回。但是当数据库中的字段名称 和 对象中的属性名称不一致时,就需要resultMap属性。
<!-- 最强大对象resultMap,结果封装到哪个pojo对象,type就是谁 -->
<resultMap type="Person" id="personRM">
<!-- 主键,property是对象的属性名,column是表里的字段名 -->
<id property="id" column="id"/>
<!-- 普通字段 -->
<result property="userName" column="user_name"/>
</resultMap>
<!-- 查询所有 -->
<select id="find" resultMap="personRM">
SELECT id,user_name FROM person WHERE id=#{id}
</select>
这里面column对应的是数据库的列名或别名;property对应的是结果集的字段或属性。
这就是resultMap最简单,也最基础的用法:字段映射。
自动匹配驼峰规则:
数据库字段: is_man
Javabean属性: private Integer isMan
mapper配置不需要写字段与属性的配置,会自动映射
注意:主键需要单独写,其它字段就可以直接利用驼峰规则自动映射。
mybatis:
configuration:
map-underscore-to-camel-case: true
二、构造方法:
如果你希望将结果注入构造方法里,就可以用到constructor元素。
<resultMap id="getUserByIdMap" type="User">
<constructor>
<!-- column代表数据库字段 name代表构造方法中的参数 javaType代表数据类型 -->
<idArg column="id" name="id" javaType="string"></idArg>
<arg column="username" name="name" javaType="string"></arg>
</constructor>
</resultMap>
三、对象关系:
分为一对一和一对多,分别使用resultMap提供的不同方案来处理:
1, 一对一:使用association + javaType
2, 一对多:使用collection + ofType
一对一:
比如说一个User对象对应一个身份:管理员、游客、用户等。
主实体类中要有一个关系类的字段:
private UserExtra userExtra;
和对应的get,set方法,association 将查询结果封装成对象并返回到这个字段。
<resultMap type="UserInfo" id="One21RM">
<!-- 描述主表 -->
<id column="id" property="id"/>
<result column="user_name" property="userName"/>
<result column="user_age" property="userAge"/>
<result column="user_addr" property="userAddr"/>
<!-- 描述 一对一的 UserExtra association+javaType固定搭配 -->
<association property="userExtra" javaType="UserExtra">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="work" property="work"/>
<result column="salary" property="salary"/>
</association>
</resultMap>
<!-- 多表查询 -->
<select id="One21" resultMap="One21RM">
select * from user_info a,user_extra b
where a.id=b.user_id and a.id=#{id}
</select>
一对多:
比如说一个User对象对应多种身份,一个User既是管理员同时也是用户。
主实体类中要有一个关系类的字段,用List接收:
private List<UserExtra> userExtras;
<!-- 根据用户查询用户详情 -->
<resultMap type="cn.tedu.pojo.UserInfo" id="userRM">
<id column="id" property="id"/>
<result column="user_name" property="userName"/>
<result column="user_addr" property="userAddr"/>
<result column="user_age" property="userAge"/>
</resultMap>
<!-- 一对一 -->
<resultMap type="cn.tedu.pojo.UserInfo" id="userExtraRM" extends="userRM">
<association property="userExtra" javaType="cn.tedu.pojo.UserExtra">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="work" property="work"/>
<result column="salary" property="salary"/>
</association>
</resultMap>
<!-- 根据用户id查询用户详情 -->
<select id="findExtraByUser" resultMap="userExtraRM">
select * from
userinfo t1,userextra t2
where
t1.id=t2.user_id
and t1.id=#{id}
</select>
<!-- 一对多 -->
<resultMap type="cn.tedu.pojo.UserInfo" id="ordersRM" extends="userRM">
<collection property="orders" ofType="cn.tedu.pojo.Orders">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="order_no" property="orderNo"/>
<result column="order_desc" property="orderDesc"/>
<result column="price" property="price"/>
</collection>
</resultMap>
四、自动填充关联对象
我们知道,在Mybatis解析返回值的时候。
第一步是获取返回值类型,拿到Class对象,然后获取构造器,设置可访问并返回实例,然后又把它包装成MetaObject对象。
从数据库rs中拿到结果之后,会调用MetaObject.setValue(String name, Object value) 来填充对象。
在这过程中,有趣的是,它会以.来分隔这个name属性。
如果name属性中包含.符号,就找到.符号之前的属性名称,把它当做一个实体对象来处理。
<select id="getUserList" resultType="User">
SELECT
u.id,
u.username,
u.password,
u.address,
u.email,
r.id as 'role.id',
r.name as 'role.name'
FROM
USER u
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN role r ON r.id = ur.role_id
</select>
这样,在Mybatis解析到role.id属性的时候,以.符号分隔之后发现,role别名对应的是Role对象,则会先初始化Role对象,并将值赋予id属性。