前言
現在項目中一直在用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,反正要有所區分,不然查詢的時候會查不到完整的數據。