MyBatis复杂查询的规范化实践-resultMap的规范化应用

**

示例业务关系模型

**
这是MyBatis文档中提到的一个经典例子~~

每个用户的博客 Blog,其下会发表有 N 篇博文 Post;
对于每一篇博文 Post,会对应 N 个评论 Comment,以及多种博文标签 Post_Tag;
在这里插入图片描述

  1. 建立关系数据表
    数据表的列命名采用下划线分隔形式,如 post_id

  2. 建立数据表对应的实体类

建议使用 mybatis-generator 为每个数据表生成其实体类,
我们暂且称这种对应于数据表的类为 “元对象”
在这里插入图片描述

假定应用中要获取这样的复合信息,即要查询某个博客的作者、发布的所有博文及其评论信息
目前没有一个对象结构反映这样的需求,所以,

  1. 定义业务需要的复合对象
    在这里插入图片描述

即我们的数据聚合查询接口,需要返回这样的一个对象(某博客)

Author 对应的是 domain下的Author实体类(元对象),而 Post 则是另外一个 复合对象:
在这里插入图片描述

其定义聚合了 作者,评论,标签三种 元对象,

至此,对象结构已经定义好:

Blog,Post 都是复合对象,由应用元对象组合而成;宜区分采用单独的包存放其定义:

在这里插入图片描述

这一步中,实际上是定义了我们应用中的数据查询返回的结果对象结构

  1. 定义Mapper查询接口

Blog selectBlogDetails(@Param(“id”) Integer id);

  1. Mapper XML中定义SQL查询
    在这里插入图片描述

resultMap detailedBlogResultMap是最顶层的映射

选取查询的基准表,此处为 Blog,连接所需的其他数据表(需要的字段出处)写出查询语句

其中,采用如下的规范:
1)为查询的数据表定义别名;
2)为结果集定义字段别名,以数据表名前缀 + 字段名,如 blog_id,对应的是blog表的id字段;
3)来自同一数据表的字段在查询语句中放在一起;
这样规范的好处见后续

至此,查询语句可以从数据库中取得含目标数据集的临时表,简单表示为如下结构:
在这里插入图片描述

  1. ORM 映射

现在,就是要利用强大的 resultMap 建立 5中的数据表 与 对象模型之间的映射关系

建立映射,
1)采取从高到低的定义顺序
2)采用反映对象模型结构的 resultMap 来定义
3)建立 resultMap 树形定义

顶级 detailedBlogResultMap 的定义如下:
在这里插入图片描述
property:对象模型中的属性名
column:对应查询结果数据中的字段名

association:一对一的关联
collection:一对多的列表结构 对比一下复合结构 Blog:

在这里插入图片描述

可以发现,resultMap的定义与Blog的结构是一一对应的关系

对于 authorResult 这个resultMap,其对应单个数据表(Author)的映射关系,我们姑且将这种resultMap称为 元映射:
在这里插入图片描述
元映射 可以看作是单表内原始数据库字段和其实体类 domain/Author 直接的映射定义

columnPrefix=“author_”

此处,是在原始数据表字段名上加上前缀 author_,作为查询结果集的字段名;
这正是我们在定义查询出的字段别名时,在字段名前面添加 表名_ 前缀的规范用处

接下来,对于Post,也是一个复合结构,其定义:
在这里插入图片描述

其对应的 resultMap 为postResultMap,是 复合映射:
在这里插入图片描述
对比对象结构和映射定义,两者也是一一对应的关系

至此,comments,tags 属性都已是 元映射,postResultMap不再包含 复合结构了。
在这里插入图片描述

因此,映射的体系结构如图,总体来看是一个树形的层次结构,

这样规范化定义:

1)结构性比较清晰自然;
2)提高复用性,减少出错;
在这里插入图片描述

总结:

1)元映射,meta resultmap,
对应的是一个数据表的映射关系;是映射树的最底层(基础层),对应的对象为数据表实体类

2)顶层映射, root resultmap,
对应的是查询结果映射,其对应的对象结构是复合的类定义

3)顶层映射下的层次结构中的复合映射,composite resultmap,
每一个也一一对应一个复合的类定义

附: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.example.bootdemo.mapper.BlogMapper">
    <!--
      查询结果列名字命名:
      1)加表名最为前缀;
      2)指定columnPrefix为表名前缀
      -->
    <select id="selectBlogDetails" resultMap="detailedBlogResultMap">
        select
               B.id as blog_id,
               B.title as blog_title,
               B.author_id as blog_author_id,
               A.id as author_id,
               A.username as author_username,
               A.password as author_password,
               A.email as author_email,
               A.bio as author_bio,
               A.favourite_section as author_favourite_section,
               P.id as post_id,
               P.blog_id as post_blog_id,
               P.author_id as post_author_id,
               P.created_on as post_created_on,
               P.section as post_section,
               P.subject as post_subject,
               P.draft as post_draft,
               P.body as post_body,
               C.id as comment_id,
               C.post_id as comment_post_id,
               C.name as comment_name,
               C.text as comment_text,
               T.id as tag_id,
               T.name as tag_name
          from Blog B
               left outer join Author A on B.author_id = A.id
               left outer join Post P on B.id = P.blog_id
               left outer join Comment C on P.id = C.post_id
               left outer join Post_Tag PT on PT.post_id = P.id
               left outer join Tag T on PT.tag_id = T.id
          where B.id = #{id}
    </select>

    <!--
      最终复杂结果映射定义
      复杂映射:对应对象的结构,层层分解
      association;collection均分解为元映射定义
      -->
    <resultMap id="detailedBlogResultMap" type="com.example.bootdemo.vo.Blog">
        <id property="id" column="blog_id" />
        <result property="title" column="blog_title"/>
        <association property="author" resultMap="authorResult" columnPrefix="author_" />
        <collection property="posts" resultMap="postResultMap" />
    </resultMap>

    <resultMap id="postResultMap" type="com.example.bootdemo.vo.Post">
        <id property="id" column="post_id"/>
        <result property="subject" column="post_subject"/>
        <association property="author" resultMap="authorResult" columnPrefix="author_" />
        <collection property="comments" resultMap="commentMap" columnPrefix="comment_" />
        <collection property="tags" resultMap="tagMap" columnPrefix="tag_" />
    </resultMap>

    <!--
      元映射定义
      -->
    <resultMap id="commentMap" type="Comment">
        <id property="id" column="id"/>
        <result property="postId" column="post_id" />
        <result property="name" column="name" />
        <result property="text" column="text" />
    </resultMap>
    <resultMap id="tagMap" type="Tag">
        <id property="id" column="id"/>
        <result property="name" column="name" />
    </resultMap>
    <resultMap id="authorResult" type="Author">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="password" column="password"/>
        <result property="email" column="email"/>
        <result property="bio" column="bio"/>
        <result property="favouriteSection" column="favourite_section"/>
    </resultMap>
</mapper>

版权声明:本文为weixin_39354876原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。