MyBatis 多对多查询

MyBatis 多对多查询

最近的项目重新用到了 Mybatis, 之前的知识点稍微有点忘记了,在此记录一下。

MyBatis 的多对多查询本质上就是两个一对多的查询,使用 collection 集合可以解决一对多 查询,使用中间表转成一对多的查询。

下面以一个例子讲解下,一篇文章有多个分类,一个分类下有多篇文章,因此需要中间表来保存关系。

entity

Posts(文章)

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Posts implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 标题
     */
    private String name;

    /**
     * 摘要
     */
    private String summary;

    /**
     * 内容
     */
    private String content;

    /**
     * 封面
     */
    private String cover;

    /**
     * 不允许评论
     */
    @TableField("disallowComment")
    private Boolean disallowComment;

    /**
     * 置顶文章
     */
    @TableField("topPriority")
    private Boolean topPriority;

    /**
     * 排序ID
     */
    @TableField("serID")
    private Integer serID;

    /**
     * 文章状态,1正常,0不正常
     */
    private Integer state;

    /**
     * 创建时间
     */
    @TableField("addTime")
    private LocalDateTime addTime;

    /**
     * 发布时间
     */
    @TableField("releaseTime")
    private LocalDateTime releaseTime;

    /**
     * 最后更新时间
     */
    @TableField("updateTime")
    private LocalDateTime updateTime;

    /**
     * 文章分类
     */
    @TableField(exist = false)
    private List<PostCategories> categories;

PostsCategories(文章分类)

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class PostCategories implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 分类名称
     */
    @NotBlank(message = "分类名称不能为空")
    private String name;

    /**
     * 描述
     */
    private String des;

    /**
     * 状态
     */
    private Boolean state;

    /**
     * 排序
     */
    @TableField("serID")
    private Integer serID;

    @TableField("addTime")
    private LocalDateTime addTime;

    @TableField("updateTime")
    private LocalDateTime updateTime;

    private List<Posts> posts;
}

PostsCategoriesRelation(中间表)

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class PostCategoriesRelation implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 文章ID
     */
    @TableField("postID")
    private Integer postID;

    /**
     * 文章分类ID
     */
    @TableField("categoryID")
    private Integer categoryID;
}

mapper(查询文章列表)

@Mapper
@Repository
public interface PostsMapper extends BaseMapper<Posts> {

    List<Posts> getPostsMap(Map<String, Object> map);

}

mapper.xml(查询文章以及文章下的分类)

在这里查询的是文章下的分类,对于文章自身而言分类是一对多的关系,因此使用 List categories 保存文章分类到 Posts 中。

collection的几个重要的属性

  • property: 在实体类中的关联的字段名称,这里即是 categories。
  • ofType: 关联的字段的类型,这里即是 PostCategories。
  • column: column="{prop1=col1,prop2=col2}", 指定多个参数给嵌套的select语句
  • select: 嵌套的select语句。
<!-- 查询语句,由于查询时需要传入 PostCategories 的条件,即从表的条件,所以需要进行左连接,反之则可以去掉 -->
<select id="getPostsMap" resultMap="postsMap">
    SELECT DISTINCT
    p.id,
    p. NAME,
    p.summary,
    p.content,
    p.cover,
    p.disallowComment,
    p.topPriority,
    p.serID,
    p.state,
    p.addTime,
    p.releaseTime,
    p.updateTime
    FROM
    posts p
    LEFT JOIN post_categories_relation pcr ON p.id = pcr.postID
    LEFT JOIN post_categories pc ON pcr.categoryID = pc.id
    <where>
        <if test="name != null">
            AND p.name LIKE CONCAT('%',#{name},'%')
        </if>
        <if test="disallowComment != null">
            AND p.disallowComment = #{disallowComment}
        </if>
        <if test="topPriority != null">
            AND p.topPriority = #{topPriority}
        </if>
        <if test="state != null">
            AND p.state = #{state}
        </if>
        <!-- PostCategories的查询条件 -->
        <if test="categoryID != null">
            AND pc.id = #{categoryID}
        </if>
    </where>
    order by p.serID asc, p.releaseTime desc
    <if test="current != null">
        LIMIT #{current}, #{pages}
    </if>
</select>

<!--resultmap,用于结果映射 -->
<resultMap id="postsMap" type="com.xy.erp.saas.userserver.entity.Posts">
    <result property="id" column="id"></result>
    <result property="name" column="name"></result>
    <result property="summary" column="summary"></result>
    <result property="content" column="content"></result>
    <result property="cover" column="cover"></result>
    <result property="disallowComment" column="disallowComment"></result>
    <result property="topPriority" column="topPriority"></result>
    <result property="serID" column="serID"></result>
    <result property="state" column="state"></result>
    <result property="addTime" column="addTime"></result>
    <result property="releaseTime" column="releaseTime"></result>
    <result property="updateTime" column="updateTime"></result>
    <!-- collection集合,嵌套的查询语句为getPostsCategories -->
    <collection property="categories" ofType="com.xy.erp.saas.userserver.entity.PostCategories" select="getPostsCategories" column="{postID=id}">
    </collection>
</resultMap>

<!-- 嵌套的select语句,参数由 collection 的 column 传递进来 -->
<select id="getPostsCategories" resultType="com.xy.erp.saas.userserver.entity.PostCategories">
    SELECT pc.id, pc.name
    FROM
    posts p
    LEFT JOIN post_categories_relation pcr ON p.id = pcr.postID
    LEFT JOIN post_categories pc ON pcr.categoryID = pc.id
    where p.id = #{postID}
</select>

返回结果

此时,调用 getPostsMap(Map<String, Object> map) 方法,返回结果如下所示, Posts 中包含 categories的 list。

{
    "id": 8,
    "name": "三体",
    "summary": "跨时代的科幻巨著",
    "content": "围绕三体文明的科幻对决",
    "cover": null,
    "disallowComment": false,
    "topPriority": false,
    "serID": 0,
    "state": 1,
    "addTime": "2020-11-02T15:58:33",
    "releaseTime": null,
    "updateTime": "2020-11-04T10:47:02",
    "categories": [
        {
            "id": 1,
            "name": "古典小说",
            "des": null,
            "state": null,
            "serID": null,
            "addTime": null,
            "updateTime": null
        },
        {
            "id": 3,
            "name": "写实",
            "des": null,
            "state": null,
            "serID": null,
            "addTime": null,
            "updateTime": null
        }
    ],
}

反之, 根据文章分类查询文章的list也是类似的写法,这里便不再赘述。

上一篇:ECS进阶训练营-day1(如何安装vsftpd)


下一篇:Mybatis-plus中的常用注解