理解思路
之前学习的MyBatis查询中,查询的如果是单个实体/实体集合,那么就把结果类型resultType写为com.samarua.domain.User/user;查询的如果是某个单一的属性值,那么就把结果类型resultType写为java.lang.Integer/int…那么,如果是多表的联合查询,结果集是一大张联合后的表(大表的字段是Users和Orders的结合),结果类型resultType该怎么写呢?
通过两处巧妙的设计思路,就能优雅的转化掉这个问题:
(1)实体类的属性编写
假设一个Order订单只属于一个用户User,Orders表中的uid字段对应Users表的id字段,这就是一对一的关系。那么,我们在设计实体类Order时,不要这样写:
public class Order {
private int id;
private String ordertime;
private double total;
// 一个订单对应一个uid
private int uid;
//...
}
而是这样编写:
public class Order {
private int id;
private String ordertime;
private double total;
// 一个订单对应一个User
private User user;
//...
}
这样有一个好处,那就是我们可以将resultType改为resultMap并将值写为Order,那另一半联合表(即User)呢?正是Order实体的一个属性!!!
(2)表字段与实体属性的匹配
我们使用resultType时,表字段和实体属性是根据名称进行自动匹配的;而当我们使用resultMap时,需要我们手动将表字段(column)和实体属性(property)进行对应匹配——这种要求是合理的,因为多表联合成的大表,字段名众多,很难保证在sql与java二者中保持名称完全一致。
下面这个例子说明了如何包装出一个resultMap,并进行字段与属性的名称匹配:
<resultMap id="orderMap" type="order">
<!-- column为查询结果的字段名,property为实体的属性名 -->
<!-- id只是比result多了主键语义,不用过多纠结 -->
<id column="id" property="id"/>
<result column="ordertime" property="ordertime"/>
<result column="total" property="total"/>
<result column="uid" property="user.id"/>
<result column="username" property="user.username"/>
<result column="password" property="user.password"/>
<result column="birthday" property="user.birthday"/>
</resultMap>
<select id="findAll" resultMap="orderMap">
select * from orders o, users u where o.uid = u.id
</select>
或许在配置名称匹配时你会无从下手,这里有一个屡试不爽的技巧,即先在mysql中进行查询得到这张表的结构,再对照着这张大表的字段名,对应上实体属性名:
一对一查询
Demo:一个订单只属于一个用户
SQL查询及其结果:
select * from orders o, users u where o.uid = u.id
代码编写:
public class Order {
private int id;
private String ordertime;
private double total;
// 一个订单对应一个User
private User user;
//...
}
<!-- 写法1 -->
<resultMap id="orderMap" type="order">
<id column="id" property="id"/>
<result column="ordertime" property="ordertime"/>
<result column="total" property="total"/>
<result column="uid" property="user.id"/>-->
<result column="username" property="user.username"/>
<result column="password" property="user.password"/>
<result column="birthday" property="user.birthday"/>
</resultMap>
<!-- 写法2 -->
<resultMap id="orderMap" type="order">
<id column="id" property="id"/>
<result column="ordertime" property="ordertime"/>
<result column="total" property="total"/>
<association property="user" javaType="user">
<result column="uid" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
</association>
</resultMap>
<select id="findAll" resultMap="orderMap">
select * from orders o, users u where o.uid = u.id
</select>
一对多查询
Demo:一个用户同时拥有多个订单
SQL查询及其结果:
select *, o.id oid from users u left join orders o on o.uid = u.id
代码编写:
public class User {
private int id;
private String username;
private String password;
private String birthday;
// 一个用户拥有多个订单
private List<Order> orderList;
//...
}
<resultMap id="userMap" type="user">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<collection property="orderList" ofType="order">
<result column="oid" property="id"/>
<result column="ordertime" property="ordertime"/>
<result column="total" property="total"/>
</collection>
</resultMap>
<select id="findAll" resultMap="userMap">
select *, o.id oid from users u left join orders o on o.uid = u.id
</select>
多对多查询
Demo:一个用户拥有多个角色,多个用户也可能是同一个角色
SQL查询及其结果:
select * from users u, roles r, user_role_relation ur where ur.userid = u.id and ur.roleid = r.id
代码编写:
public class User {
private int id;
private String username;
private String password;
private String birthday;
// 一个用户拥有多个角色
private List<Role> roleList;
//...
}
<resultMap id="userRoleMap" type="user">
<id column="userid" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<collection property="roleList" ofType="role">
<id column="roleid" property="id"/>
<result column="rolename" property="rolename"/>
<result column="roledesc" property="roledesc"/>
</collection>
</resultMap>
<select id="findUserRole" resultMap="userRoleMap">
select * from users u, roles r, user_role_relation ur where ur.userid = u.id and ur.roleid = r.id
</select>
总结
一对一 | <resultMap>+<association> |
一对多 | <resultMap>+<collection> |
多对多 | <resultMap>+<collection> |