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
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也是类似的写法,这里便不再赘述。