三、MyBatis系列:Mapper 映射 之 多级关联查询结果映射

现在有这么几张表,员工表(user)、订单(orders)、订单明细(orderdetails)、产品信息(items)它们的物理模型图如下:

希望能查询出某些用户下的订单详细信息,而且希望能一条SQL查出所有相关的数据,并映射到POJO实体中。
返回的结果应该包含用户信息、订单及明细、相应产品信息。
数据映射为实体结构如下:

 1 package cn.xleos.mybatis.po;
 2 
 3 public class User {
 4     private int id;
 5     private String username;
 6     private Date birthday;
 7     private String sex;
 8     private String address;
 9     private List<Order> orders;  // 一个用户关联多个订单
10 }
11 public class Order {
12     private int id;
13     private User user; // 订单所属的用户.
14     private int number;
15     private Date createtime;
16     private List<OrderDetail> details; // 一个订单关联多个订单明细
17 }
18 public class OrderDetail {
19     private int id;
20     private Order order;  // 明细所属的订单
21     private Item item;  // 每个订单明细关联一个产品信息.
22     private int number;
23 }
24 public class Item {
25     private int id;
26     private String name;
27     private Float price;
28     private String detail;
29 }

现在来看看这个mapper的映射配置如何编写,注意示例中的以下几点:
1、constructor  实体的构造方法
2、autoMapping  自动属性映射
3、collection  集合属性的映射
4、association  关联属性的映射
5、mapUnderscoreToCamelCase 是否开启自动驼峰命名规则,全局配置.

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.3//EN"
 3 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 4 <mapper namespace="test">
 5     <!-- 定义一个返回结果映射,告诉 MyBatis你希望的映射方式.
 6          1. type 是你希望结果映射到的POJO类型;
 7          2. autoMapping 默认为 false;
 8      -->
 9     <resultMap type="cn.xleos.mybatis.po.User" id="userOrderDetailMap" autoMapping="true">
10         <!-- 当你希望以自定构造方法来创建实例时,就需要该配置节,如:User(Integer id, String username).
11              正如期望的那样,为构造方法传递参数值,是按照配置节顺序传入的.
12             >idArg: 传入一个做为主键值的参数. 
13             >arg: 传入一个普通的参数值.
14          -->
15         <constructor>
16             <!-- 使用 User(Integer id)构造函数来传入 id 参数.
17                 >这里有个地方要注意,无论 javaType 设置的值为 int 或 integer 都是 java.lang.Integer 的别名.
18                 >这样在 User 类型中就不能使用 int 做为 id 的类型, 否则会找不到该构造方法.
19                 >若希望在 User 类中使用 int 做为构造方法类型 User(int id),那这里的 javaType 应设置为 _int,它才是 int 类型别名.
20                 >还需要注意的是: 其它类型也可能存在相同的问题.
21              -->
22             <idArg column="user_id" javaType="int" />
23             <arg column="username" javaType="String" />
24         </constructor>
25     
26         <!-- 当构造方法中没有定义一个主键做为参数,那么你可能需要使用以下的方式配置主键属性. -->
27         <!-- <id property="id" column="user_id" /> -->
28         
29         <!-- 默认情况下只有配置了 result 才会将数据绑定至该属性.
30             >只有 autoMapping 设置为 true 时, 即使不配置 sex/address,也会自动绑定属性.会忽略大小写的.
31             >还有一种情况是:数据字段命名时常常将多个字段名使用下划线间隔,如:user_name
32             >如果希望能正确的映射到 username 属性中,需要在全局配置文件中设置: mapUnderscoreToCamelCase=true
33         -->
34           <result property="birthday" column="birthday"  />
35         <!--
36         <result column="sex" property="sex" />
37         <result column="address" property="address" />
38         -->
39         
40         <!-- collection 表示你将要映射一个 List<E> 类型的属性, 这里映射到的另一个resultMap; -->
41         <collection property="orders" resultMap="orderDetailMap" />
42     </resultMap>
43     <!-- 表单及明细的结果映射 -->
44     <resultMap type="cn.xleos.mybatis.po.Order" id="orderDetailMap">
45         <id property="id" column="orders_id" />
46         <result column="createtime" property="createtime" />
47         <result column="number" property="number" />
48         <!-- 表单所属用户的关联属性映射 -->
49         <association property="user" resultMap="userOrderDetailMap" />
50         <!-- 表单明细集合的结果映射 -->
51         <collection property="details" ofType="cn.xleos.mybatis.po.OrderDetail">
52             <id property="id" column="detail_id" />
53             <result property="number" column="items_num" />
54             <!-- 明细所属表单的关联属性映射 -->
55             <association property="order" column="orders_id" resultMap="orderDetailMap" />
56             <!-- 明细所属产品的关联属性映射 -->
57             <association property="item" javaType="cn.xleos.mybatis.po.Item">
58                 <id property="id" column="items_id" />
59                 <result property="name" column="name" />
60                 <result property="price" column="price" />
61                 <result property="detail" column="detail" />
62             </association>
63         </collection>
64     </resultMap>
65     
66     <!-- 您必须定义 resultMap,否则将无法得到你预期的结果. -->
67     <select id="getUserOrderDetails" resultMap="userOrderDetailMap">
68         SELECT
69         `user`.id AS user_id,
70         `user`.username AS user_name,
71         `user`.sex AS sex,
72         `user`.birthday AS birthday, 
73         `user`.address AS address,
74         orders.id AS orders_id,
75         orders.createtime,
76         orders.number,
77         orderdetail.id AS detail_id,
78         orderdetail.items_num,
79         items.id AS items_id,
80         items.`name`,
81         items.price,
82         items.detail
83         FROM orderdetail
84         INNER JOIN orders ON orders.id = orderdetail.orders_id
85         INNER JOIN `user` ON `user`.id = orders.user_id
86         INNER JOIN items ON items.id = orderdetail.items_id
87     </select>
88 </mapper>

 数据查询结果与实体映射的关系,通过下图可以很容易理解。

  • A 数据源会去重,生成一个 user 对象
  • B 数据源会去重,生成 user 对象中的 orders 集合中的记录。
  • 在生成 order 对象的 user 属性时,会从一级缓存获取 user 对象,它的 key 就是 user_id
  • C 数据源会去重,生成 order 对象中的 details 集中中的记录;
  • D 数据源会生成 detail 对象的 item 关联属性;

 

posted @ 2015-06-27 18:24  夏亮  阅读(1365)  评论(0编辑  收藏  举报