十六、Mybatis之“多对多”

(一)案例介绍
  我在开发一个权限管理系统,里面涉及到为“用户组”分配可操作“菜单项”,这里面的两个实体“用户组”和“菜单项”就是多对多的关系:一个用户组可以分配多个菜单项,一个菜单项可以分配给多个用户组。
(二)表设计
  1.用户组

CREATE TABLE `sys_group` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(50) DEFAULT NULL COMMENT '组名',
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

  2.菜单项

CREATE TABLE `sys_menu` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(50) DEFAULT NULL COMMENT '组名',
  `url` varchar(200) DEFAULT NULL COMMENT '访问地址',
  `parent_id` int(11) DEFAULT NULL COMMENT '父菜单ID',
  `order_num` int(2) DEFAULT NULL COMMENT '排序数字',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

  3.为用户组分配菜单项表

CREATE TABLE `sys_group_menu` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `group_id` int(11) DEFAULT NULL COMMENT '组id',
  `menu_id` int(11) DEFAULT NULL COMMENT '菜单id',
  PRIMARY KEY (`id`),
  KEY `fk_sys_group_idx` (`group_id`),
  KEY `fk_sys_menu_idx` (`menu_id`),
  CONSTRAINT `fk_sys_group` FOREIGN KEY (`group_id`) REFERENCES `sys_group` (`id`),
  CONSTRAINT `fk_sys_menu` FOREIGN KEY (`menu_id`) REFERENCES `sys_menu` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

  备注:对于对多对关系,我们一般选择冗余一张表,来建立两个实体之间的关系!

(三)Java对象
  1.用户组(Group)

package com.imooc.bean;

import java.util.List;

/**
 * @author 咸鱼
 * @date 2018/6/18 17:45
 */
public class Group extends BaseBean {
    /**
     * 用户组名称
     */
    private String name;
    /**
     * 一对多关系映射(Group和Menu并不直接产生联系,而是靠中间表产生联系)
     */
    private List<Menu> menuList;
}

  2.菜单项(Menu)

package com.imooc.bean;

import com.fasterxml.jackson.annotation.JsonInclude;

import java.util.List;

/**
 * @author 咸鱼
 * @date 2018/6/20 7:37
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Menu extends BaseBean {
    /**
     * 菜单名称
     */
    private String name;
    private String url;
    private Integer parentId;
    /**
     * 排序权重
     */
    private Integer orderNum;
    /**
     * 一对多关系映射(Group和Menu并不直接产生联系,而是靠中间表产生联系)
     */
    private List<Group> groupList;
}

(四)Mybtis映射文件(我们以查询“用户组”为例)

    <resultMap id="GroupMap" type="Group">
        <id column="g_id" property="id"/>
        <result column="g_name" property="name"/>
        <!-- 1对多映射 -->
        <collection property="menuList" ofType="Menu">
            <id column="m_id" property="id"/>
            <result column="m_name" property="name"/>
            <result column="m_url" property="url"/>
            <result column="m_parent_id" property="parentId"/>
            <result column="m_order_num" property="orderNum"/>
        </collection>
    </resultMap>

(五)具体的查询sql语句(我们以查询“用户组”为例)

<select id="selectGroups" parameterType="Group" resultMap="GroupMap">
        SELECT g.id g_id,g.name g_name,m.id m_id,m.name m_name,m.url m_url,m.parent_id m_parent_id,m.order_num m_order_num
        FROM sys_group g
        LEFT JOIN sys_group_menu gm ON g.id=gm.group_id
        LEFT JOIN sys_menu m ON m.id=gm.menu_id
        <where>
            <if test="id != null">AND g.id=#{id}</if>
            <if test="name != null and !&quot;&quot;.equals(name.trim())">AND g.`name`=#{name}</if>
        </where>
        ORDER BY CONVERT(g.`name` using gbk) COLLATE gbk_chinese_ci
    </select>

(六)易错点
  1.在配置映射表的时候,Group会有一个id,Menu也会有一个id,若我们在配置映射表时,对“column”属性不加以区分,那么Mybatis不知道将查询到的id放到哪里(因为它是根据别名来将值放到对应的属性的)。解决办法:将“column”配置成不同的别名,然后在查询的时候,将对应的字段后面放上别名即可!
  2.sql语句的返回类型一定要配置成映射表!!!(在这里我错了好多次),若不配置成这样,那么出来的结果,集合成员变量肯定为null。
  3.这里为了保证用户组不管分配没分配菜单都能被查询出来,所以,使用的是“LEFT JOIN”,具体和“=”的区别,参见我另外一篇七、“where g.id=m.id”与“LEFT JOIN sys_menu m ON g.id=m.id”区别?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值