经常会用到mybatis的Collection标签来做级联查询或递归查询,现通过一个伪例来简单的说明一下使用中的关键点:

首先先列出三个表,给出一个场景:

1,角色表 t_role( id,name )  
2,菜单表 t_menu( id, name, pid ) 菜单表是个有个pid,指向上级菜单的id,所以是个树形表
3,角色菜单关联表 t_role_menu( role_id, menu_id ) 角色和菜单对多关联
java对象如下:

//菜单对象
@Set
@Get
public class Menu {
private Long id;
private String name;
private Long pid;
private List<Menu> subMenus;//子菜单集合
} //角色对象
@Set
@Get
public class Role {
private Long id;
private String name;
private List<Menu> menus;//关联菜单集合
}

一,简单关联查询:根据角色id查询角色,以及角色所关联的菜单的集合;

mapper xml文件配置如下:

<!--1,根据主键查询角色,及其关联的菜单-->
<select id="selectRoleById" parameterType="Long" resultMap="RoleResultMap">
select * from t_role where id = #{id}
</select> <!--2,角色结果映射-->
<resultMap id="RoleResultMap" type="Role">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<collection property="menus" column="id" ofType="Menu" select="selectMenuByRoleId"/>
</resultMap> <!--3,根据角色id,查询菜单集合-->
<select id="selectMenuByRoleId" parameterType="Long" resultMap="MenuResultMap">
select a.* from t_menu a
join t_role_menu b on a.id = b.menu_id and b.role_id=#{roleId}<!--roleId这个变量名称可以随便写-->
</select> <!--4,菜单结果映射-->
<resultMap id="MenuResultMap" type="Menu">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="pid" jdbcType="BIGINT" property="name" />
</resultMap>

指定的角色以及关联的菜单集合,调用顺序已经按照序号1234排列,其中需要注意的有两点:

1,第2步,collection标签中的column=“id”,id是role查询结果映射中的column,而不是property;

2,第3步,参数#{roleId},这个名称可以随便起;

通过上边的例子,可以查询出角色关联的菜单,但是每个菜单对象的子菜单集合都是null,因为没有查询菜单的子菜单,下面引入下面的场景:递推查询。

二,递归查询(特殊的关联查询):根据菜单id查询菜单树,自己调用自己

mapper xml文件配置如下:

<!--1,根据主键查询菜单-->
<select id="selectMenuTreeById" parameterType="Role" resultMap="MenuResultMap">
select * from t_menu where id = #{id}
</select> <!--2,菜单结果映射-->
<resultMap id="MenuResultMap" type="Menu">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="pid" jdbcType="BIGINT" property="name" />
<collection property="subMenus" column="id" ofType="Menu" select="selectSubMenuByPid"/>
</resultMap> <!--3,查询id查询菜单-->
<select id="selectSubMenuByPid" parameterType="Role" resultMap="MenuResultMap">
select * from t_menu where pid = #{pid}
</select>

TreeById”方法就完成菜单树的调用,相比上边的关联查询少了一步结果映射,这是因为父查询和子查询的映射结果相同。注意的点也在于此。

三,多字段关联:把上边的递归查询稍微变一下,不通过菜单的id查询菜单树,而是查询指定角色的菜单树,应该怎么改一下呢?

我们把第一步的方法,改一下,参数变成角色id,并且通过关联表进行关联:

<!--1,根据角色id查询菜单-->

<select id="selectMenuByRoleId" parameterType="Long" resultMap="MenuResultMap">
select a.* from t_menu a
join t_role_menu b on a.id = b.menu_id and b.role_id=#{roleId}
</select>

这样是不是就可以了?答案是:NO!

因为这样只能保证根菜单是和角色关联的,下边的子菜单并不能保证与角色关联,对应的地推查询也需要增加关联,所以就引出了“多字段关联”的情况,完整的mapper xml文件配置如下:

<!--1,根据角色id查询菜单-->
<select id="selectMenuByRoleId" parameterType="Long" resultMap="MenuResultMap">
select a.*, b.role_id
from t_menu a
join t_role_menu b on a.id = b.menu_id and b.role_id=#{roleId}
</select> <!--2,菜单结果映射-->
<resultMap id="MenuResultMap" type="Menu">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="pid" jdbcType="BIGINT" property="name" />
<!--关联参数,与java实体没有关系-->
<result column="role_id" jdbcType="BIGINT" />
<collection property="subMenus" column="{pid=id,roleId=role_id}" ofType="Menu" select="selectSubMenuByPid"/>
</resultMap> <!--3,查询id查询菜单-->
<select id="selectSubMenuByPid" parameterType="java.util.Map" resultMap="MenuResultMap">
select a.*, b.role_id
from t_menu a
join t_role_menu b on a.id = b.menu_id and b.role_id=#{roleId}
where a.pid = #{pid}
</select>

1,需要在第一步的时候把关联的角色id(role_id)查出来,放到结果映射中,如第2步所示,增加了一个result标签,column就是role_id,但是不要加property(如果实际需要的话也可以加,但是需要在java对象中增加该属性),它不映射到java对象上,只是作为关联字段。

2,第2步,在collection标签中需要增加关联字段,多个column的写法如上所示,k=v的形式,k就是参数名,v就是引用的结果字段(column而不是property),同时在子查询中的参数类型需要改成Map,并且参数名不能随便写了,需要根据collection中的指定的参数名来使用。

MyBatis Collection小记—— 关联查询、递归查询、多字段关联的更多相关文章

  1. MyBatis关联查询,一对多关联查询

    实体关系图,一个国家对应多个城市 一对多关联查询可用三种方式实现: 单步查询,利用collection标签为级联属性赋值: 分步查询: 利用association标签进行分步查询: 利用collect ...

  2. MyBatis学习总结(三)——多表关联查询与动态SQL

    在上一章中我们学习了<MyBatis学习总结(二)——MyBatis核心配置文件与输入输出映射>,这一章主要是介绍一对一关联查询.一对多关联查询与动态SQL等内容. 一.多表关联查询 表与 ...

  3. MyBatis入门(二)—— 输入映射和输出映射、动态sql、关联查询

    一.输入映射和输出映射 1. parameterType(输入类型) 1.1 传递简单类型 <select id="getUserById" parameterType=&q ...

  4. MyBatis关联查询、多条件查询

    MyBatis关联查询.多条件查询 1.一对一查询 任务需求; 根据班级的信息查询出教师的相关信息 1.数据库表的设计 班级表: 教师表: 2.实体类的设计 班级表: public class Cla ...

  5. MyBatis从入门到放弃四:一对多关联查询

    前言 上篇学习了一对一关联查询,这篇我们学习一对多关联查询.一对多关联查询关键点则依然是配置resultMap,在resultMap中配置collection属性,别忽略了ofType属性. 搭建开发 ...

  6. MyBatis:一对多关联查询

    MyBatis从入门到放弃四:一对多关联查询 前言 上篇学习了一对一关联查询,这篇我们学习一对多关联查询.一对多关联查询关键点则依然是配置resultMap,在resultMap中配置collecti ...

  7. MyBatis关联查询,一对一关联查询

    数据库E-R关系 实体类 public class City { Long id; String name; Long countryId; Date lastUpdate; } public cla ...

  8. 关联查询 join on 和比较运算符 in

    join on多表之间的关联查询 写法select 字段 from 表1 t join 表2 s on t.字段1 = s.字段1 where 条件: 也可以这么写select 字段 from 表1 ...

  9. Ibatis组合键关联查询

    在使用Ibatis时,会经常遇到关联查询,一般有两种解决方案: 使用代码进行关联查询 使用Ibatis配置文件进行关联查询 使用代码进行关联查询不作解释,本次主要是针对Ibatis配置文件进行关联查询 ...

随机推荐

  1. WLAN-无线路由综合应用

    一.实验目的 掌握综合应用的配置 二.实验仪器设备及软件 实验仪器设备:路由器.三层交换机.3台二层交换机.AC.3台AP 软件:ensp   三.实验原理   四.实验内容与步骤 AC配置: [AC ...

  2. .Net Core微服务——网关(1):ocelot集成及介绍

    网关是什么 简单来说,网关就是暴露给外部的请求入口.就和门卫一样,外面的人想要进来,必须要经过门卫.当然,网关并不一定是必须的,后端服务通过http也可以很好的向客户端提供服务.但是对于业务复杂.规模 ...

  3. 写给初学者的Linux errno 错误码机制

    不同于Java的异常处理机制, 当你使用C更多的接触到是基于错误码的异常机制, 简单来说就是当调用的函数发生异常时, 程序不会跳转到一个统一处理异常的地方, 取而代之的是返回一个整型错误码. 可能会有 ...

  4. vue配置请求拦截器和响应拦截器

    首先确保我们已经设置的store.js进行值的存取,这时候我们需要配置请求和响应的拦截器设置 main.js import Vue from 'vue' import App from './App' ...

  5. 九. Go并发编程--context.Context

    一. 序言 前几篇中提到 等待多个 goroutine 协作的方式可以使用WaitGroup. 但是有一种场景我们无论是使用Mutex, sync/Once,都无法满足. 场景如下 现在有一个 Ser ...

  6. Linux驱动实践:带你一步一步编译内核驱动程序

    作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...

  7. [loj6736]最小连通块

    定义$f(S)$表示点集$S$的最小连通块 做法1 通过对所有节点判定,可以在$n$次询问中求出具体的$f(S)$ 对于$x\ne y$,显然$(x,y)\in E$当且仅当$f(\{x,y\})=\ ...

  8. [hdu6391]Lord Li's problem

    首先发现结果与需要改变的具体位置无关,只和需要改变的位置的个数有关,因此设f[i][j]表示选取了i个数字异或结果有j个1,只要分析接下来选择的数和这j个1有几个重合即可: 1. 三个数字全部重合,即 ...

  9. [loj3315]抽卡

    令$S$表示对于某一种抽卡顺序中某一段长度为$k$的段全部被抽到的时间(这里没有期望)所构成的集合,根据$min-max$容斥的公式,有$E(\min(S))=\sum_{T\subseteq S}( ...

  10. [源码解析] PyTorch 分布式(9) ----- DistributedDataParallel 之初始化

    [源码解析] PyTorch 分布式(9) ----- DistributedDataParallel 之初始化 目录 [源码解析] PyTorch 分布式(9) ----- DistributedD ...