• MyBatis Collection小记—— 关联查询、递归查询、多字段关联


     经常会用到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中的指定的参数名来使用。

  • 相关阅读:
    Ant 执行 exec cmd.exe 时路径包含空格的问题
    时区时差换算(GMT,UTC,PST,PDT)
    windows 共存多个位数不同的jdk时,eclipse的报错对应措施
    Windows下查询指定端口进程,并杀死
    关于windows的jdk
    第一阶段工作总结
    mac配置git mergetool为p4merge(2013笔记整理)
    ubuntu 14.04 安装压缩包版mysql
    关于微信公众号内嵌网页的几个meta标签
    关于js的keyCode
  • 原文地址:https://www.cnblogs.com/edda/p/14588146.html
Copyright © 2020-2023  润新知