上篇文章说了MyBatis中的一对一查询的两种方法,这里总结一下MyBatis中一对多和多对一的查询方法。
业务还用上篇文章中的订单业务来分析,表结构如下:
如上图订单和用户的关系,一个订单对应多个订单明细表,这里以订单为主查询表,在查询订单的同时,查询出每个订单所包含的订单明细集合,顺便把每个订单对应的用户也查询出来。(即在上篇文章的基础上,再查询出每个订单所包含的订单明细)
由于每个订单可能有多个订单明细,所以这时需要用esultMap映射结果集。如果使用resultType会很麻烦,需要去重(比如文章末尾的图片中,sql查询出的是8条记录,但实际上这8条订单明细只属于4个订单实体,所以需要手动循环、判断、去重~)。
具体用法如下:
订单实体在上篇文章的基础上,添加订单明细的集合 orderDetails:
public class Orders { private Integer id; private Integer userId; private String number; private Date createtime; private String note; private User user;//订单对应用户 private List<OrderDetail> orderDetails;//订单所包含的订单明细集合 //getter、setter }
映射文件OrdersMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.danny.mybatis.mapper.OrdersMapper" > <resultMap type="com.danny.mybatis.po.Orders" id="OrdersUserOrderDetailResultMap"> <!-- 配置映射的订单信息 --> <!-- <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> --> <!-- 配置映射的用户信息 --> <association property="user" javaType="com.danny.mybatis.po.User"> id:关联查询用户的唯一标识 column:指定唯一标识用户信息的列 property:映射到user的哪个属性 <id column="user_id" property="id"/> <result column="username" property="username"/> <result column="sex" property="sex"/> <result column="address" property="address"/> </association> <!-- 订单明细信息--> <collection property="orderDetails" ofType="com.danny.mybatis.po.OrderDetail"> <id column="orderdetail_id" property="id"/> <result column="items_id" property="itemsId"/> <result column="items_num" property="itemsNum"/> <result column="orders_id" property="ordersId"/> </collection> </resultMap> <select id="findOrdersUserOrderDetailResultMap" resultMap="OrdersUserOrderDetailResultMap" > select orders.*, user.username, user.sex, user.address, orderdetail.id orderdetail_id, orderdetail.items_id, orderdetail.items_num, orderdetail.orders_id from orders,user,orderdetail where orders.user_id=user.id and orders.id=orderdetail.orders_id </select> </mapper>
在上面resultMap配置中,共有三个部分,配置映射的订单信息、配置映射的用户信息和配置映射的订单明细信息。前两部分与上篇文章中的一致,这里不再多说。
映射Ordes中的订单集合orderDetails要用<collection></collection>进行映射,它的作用是把关联查询到的多条记录映射到集合对象中,property表示将关联查询到的多条订单明细记录映射到Orders的哪个属性中,与<association></association> 中的javaType不同,这里指定orderDetails的类型要用ofType属性,它表示指定映射到集合属性中的pojo的类型。
因为这个resultMap的配置大约有2/3的代码都与上篇文章中的resultMap一直,因此也可以跟java类似的,让这个resultMap继承已有的resultMap,如下:
<resultMap type="com.danny.mybatis.po.Orders" id="OrdersUserOrderDetailResultMap" extends="OrdersUserResultMap"> <!-- 订单明细信息--> <collection property="orderDetails" ofType="com.danny.mybatis.po.OrderDetail"> <id column="orderdetail_id" property="id"/> <result column="items_id" property="itemsId"/> <result column="items_num" property="itemsNum"/> <result column="orders_id" property="ordersId"/> </collection> </resultMap>
mapper接口
public interface OrdersMapper{ List<Orders> findOrdersUserOrderDetailResultMap() throws Exception; }
测试
@Test public void findOrdersUserOrderDetailResultMap(){ SqlSession sqlSession=sqlSessionFactory.openSession(); OrdersMapper ordersMapper=sqlSession.getMapper(OrdersMapper.class); try { List<Orders> ordersList=ordersMapper.findOrdersUserOrderDetailResultMap(); System.out.println("共查询到"+((ordersList!=null && list.size()>0)?ordersList.size():0)+"个订单"); } catch (Exception e) { e.printStackTrace(); } System.out.println(); }
上述sql语句查询出的结果为:
断点查看list中的数据如下:
虽然sql语句查询出的结果为8条数据,但实际上只有4个订单(通过id字段可以看出来),MyBatis自动把id相同的记录合并成一个订单实体,并根据resultMap中的配置,把属于同一个订单的订单明细分别放到了对应订单的订单明细集合中。
如果熟悉Hibernate的话,到了这里,您是不是也和小编觉得这跟Hibernate的配置也有些相似呢~~
如果要问多对一查询的话,实际上你已经不知不觉地实现了~订单和用户啥关系?多个订单可以属于一个用户,所以上面的配置中<association></association> 也可以实现多对一查询,不信你在好好看看上面list中的内容,第一和第二个订单所属的用户其实是同一个人:DannyHoo~