写在前面:各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢!如果我的博客对你有帮助,欢迎进行评论✏️✏️、点赞👍👍、收藏⭐️⭐️,满足一下我的虚荣心💖🙏🙏🙏 。
目录
准备测试类
不小心把已经写好的博客误删除,再简单记录一下吧,集合元素collection和关联元素association几乎是一样的,准备下测试类:
@Data
public class Order {
private int id;
private int userId;
private String orderNumber;
}
准备一个UserOrderDto接收查询结果:
@Data
public class UserOrderDto {
private int id;
private String userName;
private List<Order> orderList;
}
mapper文件代码不贴了,直接贴测试类代码:
@Test
public void collectionTest1() {
UserOrderDto userOrderDto = userMapper.selectUserOrdersBySelect(1);
System.out.println("--- userOrderDto ---" + userOrderDto);
}
同关联查询一样,集合查询也有嵌套 Select 查询、集合的嵌套结果映射和集合的多结果集(ResultSet)这三种常用写法。
集合的嵌套Select查询
先看下集合的嵌套Select查询:
UserMapper.xml:
<select id="selectUserOrdersBySelect" resultMap="userOrderResultMapBySelect">
select id,name as username
from mybatis_user
where id = #{id}
</select>
<resultMap id="userOrderResultMapBySelect" type="com.yjh.learn.mybatislearn.dto.UserOrderDto">
<collection property="orderList" column="id" select="selectOrdersByUserId"
ofType="Order"/>
</resultMap>
<select id="selectOrdersByUserId" resultType="Order">
select *
from mybatis_order
where user_id = #{userId}
</select>
如上:和使用association关联查询时几乎一样,不一样的在于:1.association换成了collection;2.有一个属性叫ofType="Order",这个属性非常重要,它用来将 JavaBean(或字段)属性的类型和集合存储的类型区分开来。 所以你可以按照下面这样来阅读映射:
<collection property="orderList" javaType="ArrayList" column="id" ofType="Order" select="selectOrdersByUserId"/>
读作: “orderList 是一个存储 Order 的 ArrayList 集合”
在一般情况下,MyBatis 可以推断 javaType 属性,因此并不需要填写。所以很多时候你可以简略成:
<collection property="orderList" column="id" ofType="Order" select="selectOrdersByUserId"/>
集合的嵌套结果映射
@Test
public void collectionTest2(){
UserOrderDto userOrderDto = userMapper.selectUserOrders(1);
System.out.println("--- userOrderDto ---" + userOrderDto);
}
<select id="selectUserOrders" resultMap="userOrderResultMap">
select u.id,u.name, o.*
from mybatis_user u
left join mybatis_order o on u.id = o.user_id
where u.id = #{id}
</select>
<resultMap id="userOrderResultMap" type="com.yjh.learn.mybatislearn.dto.UserOrderDto">
<id property="id" column="id"/>
<result property="userName" column="name"/>
<collection property="orderList" column="id" ofType="Order"
resultMap="orderResultMap"/>
</resultMap>
<resultMap id="orderResultMap" type="Order">
<id property="id" column="id"/>
<result property="userId" column="user_id"/>
<result property="orderNumber" column="order_number"/>
</resultMap>
如上查询本意是想查询用户张三的所有订单,并且从控制台打印的sql可以看出查询到了两个订单,但是实际映射完的结果却只有一个,原因就是用户表和订单表的id名称一样,这时候为了能正确映射两个订单,可以不映射订单的id,如下:
<resultMap id="orderResultMap" type="Order">
<!-- <id property="id" column="id"/>-->
<result property="userId" column="user_id"/>
<result property="orderNumber" column="order_number"/>
</resultMap>
如上,虽说查询到了两个订单,但是每个订单的id就获取不到了,在使用association和collection映射时都有这个问题,最简单的解决方式就是在表结构上将各id区分开,比如用户表的id为user_id,订单表的id为order_id,这里只改下订单表的id即可,如下:
<select id="selectUserOrders" resultMap="userOrderResultMap">
select u.id,u.name, o.*
from mybatis_user u
left join mybatis_order o on u.id = o.user_id
where u.id = #{id}
</select>
<resultMap id="userOrderResultMap" type="com.yjh.learn.mybatislearn.dto.UserOrderDto">
<id property="id" column="id"/>
<result property="userName" column="name"/>
<collection property="orderList" column="id" ofType="Order"
resultMap="orderResultMap"/>
</resultMap>
<resultMap id="orderResultMap" type="Order">
<id property="orderId" column="order_id"/>
<result property="userId" column="user_id"/>
<result property="orderNumber" column="order_number"/>
</resultMap>
再次查询的时候数据就完整了,如下:
同association一样嵌套结果映射也有简写方式,如下:
<resultMap id="userOrderResultMapSimple" type="com.yjh.learn.mybatislearn.dto.UserOrderDto">
<id property="id" column="id"/>
<result property="userName" column="name"/>
<collection property="orderList" column="id" ofType="Order">
<id property="orderId" column="order_id"/>
<result property="userId" column="user_id"/>
<result property="orderNumber" column="order_number"/>
</collection>
</resultMap>
集合的多结果集(ResultSet)
同association一样先建一个存储过程:
DELIMITER $$
CREATE PROCEDURE `uorders`(IN `userId` INTEGER)
BEGIN
SELECT * FROM mybatis_user WHERE id = userId;
SELECT * FROM mybatis_order WHERE user_id = userId;
END $$
在映射语句中,必须通过 resultSets 属性为每个结果集指定一个名字,多个名字使用逗号隔开,如下:
<select id="selectUserOrdersByResultSet" resultSets="uresult,oresult" resultMap="userResultMap1" statementType="CALLABLE">
{call uorders(#{userId,jdbcType=INTEGER,mode=IN})}
</select>
我们指定 “orderList” 集合将会使用存储在 “oresult” 结果集中的数据进行填充:
<resultMap id="userResultMap1" type="com.yjh.learn.mybatislearn.dto.UserOrderDto">
<id property="id" column="id"/>
<result property="userName" column="name"/>
<collection property="orderList" ofType="Order" resultSet="oresult" column="id" foreignColumn="user_id">
<id property="orderId" column="order_id"/>
<result property="userId" column="user_id"/>
<result property="orderNumber" column="order_number"/>
</collection>
</resultMap>
测试下:
@Test
public void test9() {
UserOrderDto userOrderDto = userMapper.selectUserOrdersByResultSet(1);
System.out.println("--- userOrderDto ---" + userOrderDto);
}
完成!
补充
返回对象中包含List属性,如List<Integer>这种怎么关联映射呢,直接贴代码了:
用户实体中增加一个roles属性,表示用户的角色集合
private List<Integer> roles;
xml中:
<resultMap id="userResultMap" type="User">
<id property="userId" column="user_id" />
<result property="userName" column="user_name" />
<collection property="orderList" ofType="Order">
<id property="orderId" column="order_id" />
<result property="userId" column="user_id" />
<result property="number" column="number" />
</collection>
<collection property="roles" ofType="integer">
<constructor>
<arg column="roles" />
</constructor>
</collection>
</resultMap>
<select id="selectUserOrdersAndRoles" resultMap="userResultMap">
select u.*,o.*,ur.role_id as roles from t_user u
left join t_orders o on u.user_id = o.user_id
left join t_user_role ur on u.user_id = ur.user_id
where u.user_id = #{userId}
</select>
如果我的博客对你有帮助,欢迎进行评论✏️✏️、点赞👍👍、收藏⭐️⭐️,满足一下我的虚荣心💖🙏🙏🙏 。