MyBatis高级查询:一对多映射collection集合实现机构-用户-角色-菜单三级嵌套查询

学习自MyBatis从入门到精通

  • 嵌套查询,会执行额外的SQL语句
    团队网站的结构关系我是做成了机构用户角色菜单三层嵌套查询,今天一天进行了实现,遇到的错误真的很多

我们知道association/collection关联的嵌套查询这种方式会执行额外外的SQL查询,映射配置会简单很多。

以实现机构-用户-角色-菜单三级嵌套查询为目标,实现嵌套查询
下面以自下而上的过程来实现一个两层嵌套的功能,并且这个自下而上的过程中,每一个方法都是独立可用的方法,最后结果都是以前一个对象为基础。把所有对象设置成延时加载,因此每个方法都可以作为普通(没有嵌套)的查询存在。

  • 首先在SysMenuMapper.xml中添加如下方法(角色-菜单嵌套查询)
  <select id="selectByRoleId" parameterType="Long" resultMap="BaseResultMap">
    select
    sm.id, sm.parent_id, sm.name, sm.perms, sm.create_by, sm.del_flag
from sys_menu sm
    inner join sys_role_menu srm
    on sm.id = srm.menu_id
    where srm.role_id = #{roleId}
  </select>

这个方法通过角色ID获取角色对应的所有菜单信息,可以在SysMenuMapper接口上增加相应的方法。这是一个很常见的方法,许多时候都需要这样一个方法来获取角色包含的所有权限信息。

  • 下一步,在SysRoleMapper.xml中配置映射对应的查询方法,代码如下
    1.映射结果
  <resultMap id="roleMenuListMapSelect" extends="BaseResultMap" type="cn.hcnet2006.blog.hcnetwebsite.bean.SysRole">
    <collection property="menuList"
                fetchType="lazy"
                column="{roleId=id}"
                select="cn.hcnet2006.blog.hcnetwebsite.mapper.SysMenuMapper.selectByRoleId"
    />
  </resultMap>

2.本层使用嵌套查询具体查询语句

  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="roleMenuListMapSelect">
    select id, name, remark, create_by, create_time, last_update_time, last_update_by,
    del_flag
    from sys_role
    where id = #{id,jdbcType=BIGINT}
  </select>

在上面的代码中注意column属性配置的{roleId=id}, roleId是select指定方法selectByRoleId中查询的参数,id是当前查询selectUserAndRoleList中查询的角色ID. selectUserAndRoleList只是一个只有一层的一对多映射设置,通过调用sysMenuMapper的seelctByRoleId方法,很轻易就实现了嵌套查询的功能。

-接下来是用户信息了,在SysUserMapper.xml中配置如下映射和查询,代码如下:
1.映射结果

    <resultMap id="userRoleMap" type="cn.hcnet2006.blog.hcnetwebsite.bean.SysUser" extends="BaseResultMap">
        <collection property="roleList"
                    fetchType="lazy"
                    column="{userId=id}"
                    select="cn.hcnet2006.blog.hcnetwebsite.mapper.SysRoleMapper.selectUserAndRoleList"/>
    </resultMap>

2.SysRoleMpper.xml中的方法

  <select id="selectUserAndRoleList" resultMap="roleMenuListMapSelect">
    select
    sr.id, sr.name, sr.remark, sr.create_by, sr.create_time, sr.last_update_time, sr.last_update_by, sr.del_flag
    from sys_role sr
    inner join sys_user_role sur
    on sr.id = sur.role_id
    where sur.user_id = #{userId}
  </select>

3.具体查询语句

  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="userRoleMap">
    select id, name, password, avator, grade, email, mobile, dept_id, (select name from sys_dept d where d.id = sys_user.dept_id) deptZh,create_by, create_time,
    last_update_time, last_update_by, del_flag
    from sys_user
    where id = #{id,jdbcType=BIGINT}
  </select>

-终于到了最顶层的机构信息接口了
1.SysUserMapper.xml中的方法

    <select id="findByDeptId"  resultMap="userRoleMap">
        select
        id, name, password, avator, grade, email, mobile, dept_id, create_by, create_time, last_update_time, last_update_by, del_flag
        from sys_user where dept_id = #{deptId}
    </select>

2.结果映射语句

  <resultMap id="deptUserMap" type="cn.hcnet2006.blog.hcnetwebsite.bean.SysDept" extends="BaseResultMap">
    <collection property="userList"
                fetchType="lazy"
                column="{deptId=id}"
                select="cn.hcnet2006.blog.hcnetwebsite.mapper.SysUserMapper.findByDeptId"/>
  </resultMap>

3.具体查询语句

<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="deptUserMap">
    select id, name, dept_logo, parent_id, create_by, create_time, last_update_time, 
    last_update_by, del_flag
    from sys_dept
    where id = #{id,jdbcType=BIGINT}
  </select>

-结果
这里我因为调整映射结果wei设置的嵌套映射结果,所以一共三层映射

{
  "code": 200,
  "msg": null,
  "data": {
  [
      {
        "id": 15,
        "name": "liubei",
        "password": "$2a$10$msaVKbkxkN4lPzUM1I1Iy.RAPCF7pmjt.OmW5sY5zKOXLzPNasS9S",
        "avator": "http://hcnet2006-file-apk.oss-cn-shenzhen.aliyuncs.com/liubei.jpg",
        "grade": "1",
        "email": "1",
        "mobile": "11",
        "deptId": 1,
        "deptZh": null,
        "createBy": "1",
        "createTime": "2020-03-05",
        "lastUpdateTime": "2020-03-05",
        "lastUpdateBy": "1",
        "delFlag": 0,
        "roleList": [
          {
            "id": 8,
            "name": "user2",
            "remark": "shiyanb",
            "createBy": "ldy",
            "createTime": "2020-03-06T11:09:52.000+0000",
            "lastUpdateTime": "2020-03-06T11:09:52.000+0000",
            "lastUpdateBy": "ldy",
            "delFlag": 0,
            "menuList": [
              {
                "id": 1,
                "parentId": 2,
                "name": "string",
                "perms": "ROLE_USER",
                "createBy": "string",
                "createTime": null,
                "lastUpdateTime": null,
                "lastUpdateBy": null,
                "delFlag": -1
              }
            ]
          }
        ]
      },
      {
        "id": 17,
        "name": "liubei1",
        "password": "$2a$10$fmmLwCZKvzOuY/e4FDM7oOwPoh0O10p5GE02qorvWhb8W4Lejhe3q",
        "avator": "http://hcnet2006-file-apk.oss-cn-shenzhen.aliyuncs.com/liubei1.jpg",
        "grade": "1",
        "email": "1",
        "mobile": "11",
        "deptId": 1,
        "deptZh": null,
        "createBy": "1",
        "createTime": "2020-03-05",
        "lastUpdateTime": "2020-03-05",
        "lastUpdateBy": "1",
        "delFlag": 0,
        "roleList": []
      }
    ]
  }
}
  • 书上原话
    特被咬注意,之所以能够根据需要查询数据,除了和fetchType设置为false有关,还和全局的aggressiveLazyLoading属性有关,这个属性在介绍association时被设置成了false,所以才会起到按需加载的作用
    通过上面的学习,大家应该对collection的用法有了一定的掌握,熟练掌握association和collection的配置,在某些情况下会给我们带来很大的便利
    这里附上全局aggressiveLazyLoading的设置方法
mybatis: #Mybaytis映射文件位置
  configuration:
    aggressive-lazy-loading: false #当参数设置为false时,对任意延迟属性的调用都将按需加载
  • bug
    在Spring Boot中这个懒加载时不管用的,但是JSON转换失败的错误照常爆出
    解决方法在其他的博客中
发布了70 篇原创文章 · 获赞 29 · 访问量 6178

猜你喜欢

转载自blog.csdn.net/weixin_43404791/article/details/104713900