前言
现在项目中一直在用Mybatis Plus框架,其中已经封装好了大部分的CRUD代码,还有很方便的条件构造器。虽然只是针对的单表操作,但也习惯了在Java代码中遍历组装数据,其实通过mybatis可以一次性、按结构查出我们需要的数据来的,下面来看看怎么做吧。
在项目中,某些实体类之间肯定有关键关系,比如一对一,一对多等。在hibernate 中用one to one
和one to many
,而mybatis 中就用association
和collection
。
association: 一对一关联(has one)
collection:一对多关联(has many)
注意,只有在做select查询时才会用到这两个标签。
已知数据库资源表数据结构如下:
每个主菜单下,包含了多级子菜单,通过parentId关联,这样就构成了一个树形结构。这也是大部分项目中默认架构设计。
比如同时有Menu.java和Meta.java两个类
资源表实体Menu如下:
package com.junya.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import com.junya.entity.domain.Meta;
import lombok.Data;
import org.apache.catalina.LifecycleState;
import java.io.Serializable;
import java.util.List;
/**
* <p>
* 权限资源表实体类
* </p>
*
* @author zhangchao
* @since 2020-05-21
*/
@Data
@TableName("menu")
public class Menu extends Model<Menu> {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@TableField("url")
private String url;
@TableField("path")
private String path;
@TableField("component")
private String component;
@TableField("name")
private String name;
@TableField("iconCls")
private String iconCls;
@TableField("parentId")
private Integer parentId;
@TableField("enabled")
private Boolean enabled;
@TableField(exist = false)
private Meta meta;
@TableField(exist = false)
private List<Menu> children;
}
children集合是存放此菜单下的所有子菜单数据。
Meta类里表示此资源的两个属性:是否存活、是否需要权限访问,如下:
package com.junya.entity.domain;
import lombok.Data;
/**
* @author ZHANGCHAO
* @date 2020/5/22 10:54
* @since 1.0.0
*/
@Data
public class Meta {
private Boolean keepAlive;
private Boolean requireAuth;
}
在映射Meta属性时用association
标签, 映射children时用collection
标签.
所以association
是用于一对一和多对一,而collection
是用于一对多的关系
MeunMapper.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.junya.mapper.MenuMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.junya.entity.Menu">
<id column="id" property="id"/>
<result column="url" property="url"/>
<result column="path" property="path"/>
<result column="component" property="component"/>
<result column="name" property="name"/>
<result column="iconCls" property="iconCls"/>
<result column="parentId" property="parentId"/>
<result column="enabled" property="enabled"/>
<!--assocication可以指定联合的JavaBean对象, property="role"指定哪个属性是联合的对象, javaType:指定这个属性对象的类型-->
<association property="meta" javaType="com.junya.entity.domain.Meta">
<result column="keepAlive" property="keepAlive"/>
<result column="requireAuth" property="requireAuth"/>
</association>
</resultMap>
<resultMap id="BaseResultMap2" type="com.junya.entity.Menu" extends="BaseResultMap">
<collection property="children" ofType="com.junya.entity.Menu">
<id column="id2" property="id"/>
<result column="url2" property="url"/>
<result column="path2" property="path"/>
<result column="component2" property="component"/>
<result column="name2" property="name"/>
<result column="iconCls2" property="iconCls"/>
<result column="parentId2" property="parentId"/>
<result column="enabled2" property="enabled"/>
<association property="meta" javaType="com.junya.entity.domain.Meta">
<result column="keepAlive2" property="keepAlive"/>
<result column="requireAuth2" property="requireAuth"/>
</association>
</collection>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, url, path, component, name, iconCls, keepAlive, requireAuth, parentId, enabled
</sql>
<select id="getMenusByHrId" resultMap="BaseResultMap2">
SELECT DISTINCT
m1.* ,
m2.id id2,
m2.component component2,
m2.enabled enabled2,
m2.iconCls iconCls2,
m2.keepAlive keepAlive2,
m2.requireAuth requireAuth2,
m2.name name2,
m2.parentId parentId2,
m2.path path2
FROM
menu m1
LEFT JOIN menu m2 ON m1.id = m2.parentId
LEFT JOIN menu_role mr ON mr.mid = m2.id
LEFT JOIN hr_role hrr ON mr.rid = hrr.rid
WHERE
hrr.hrid = #{hrid}
AND m2.enabled = TRUE
ORDER BY
m1.id,
m2.id
</select>
</mapper>
查询出的数据结构如下:
总结
- association表示的是has one的关系,一对一时使用。menu has one meta,所以在Menu的resultMap中接收Meta时应该用association;
- collection表示的是has many的关系,一对多时使用。menu has many chirdren,所以在Menu的resultMap中接收children时应该用collection 。
- 特别注意表中主键字段要有所区分,不能都写成id,比如要写成user_id、menu_id,反正要有所区分,不然查询的时候会查不到完整的数据。