MyBatis-Plus中如何使用ResultMap

如题所述

第1个回答  2022-07-13
MyBatis-Plus 对 MyBatis 基本零侵入,完全可以与 MyBatis 混合使用,这点很赞。

在涉及到关系型数据库增删查改的业务时,我比较喜欢用 MyBatis-Plus ,开发效率极高。具体的使用可以参考官网,或者自己上手摸索感受一下。

下面简单总结一下在 MyBatis-Plus 中如何使用 ResultMap 。

先看个例子:

有如下两张表:

其中, tb_hero 中的 bid 关联 tb_book 表的 id 。

下面先看 Hero 实体类的代码,如下:

注意了,我特地把 tb_hero 表中的 bid 字段映射成实体类 Hero 中的 bookId 属性。

MyBatis-Plus 打印出的 SQL 为:

没毛病, MyBatis-Plus 会根据 @TableField 指定的映射关系,生成对应的 SQL 。

MyBatis-Plus 打印出的 SQL 为:

也没毛病,可以看到生成的 SELECT 中把 bid 做了别名 bookId 。

比如现在我想连接 tb_hero 与 tb_book 这两张表,如下:

查询 MyBatis-Plus 打印出的 SQL 为:

SQL没啥问题,过滤与分页也都正常,但是此时你会发现 bookId 属性为 null ,如下:

为什么呢?

调用 BaseMapper 中内置的 selectById() 方法并没有出现这种情况啊???

回过头来再对比一下在 HeroMapper 中自己定义的查询与 MyBatis-Plus 自带的 selectById() 有啥不同,还记得上面的刚刚的测试吗,生成的SQL有啥不同?

原来, MyBatis-Plus 为 BaseMapper 中内置的方法生成SQL时,会把 SELECT 子句中 bid 做别名 bookId ,而自己写的查询 MyBatis-Plus 并不会帮你修改 SELECT 子句,也就导致 bookId 属性为 null 。

在这里就是 tb_hero 表中的 bid 字段映射成实体类 Hero 中的 bid 属性。这样当然可以解决问题,但不是本篇讲的重点。

在 @TableName 设置 autoResultMap = true

然后在自定义查询中添加 @ResultMap 注解,如下:

这样,也能解决问题。

下面简单看下源码, @ResultMap("mybatis-plus_实体类名") 怎么来的。

详情见: com.baomidou.mybatisplus.core.metadata.TableInfo#initResultMapIfNeed()

注意看上面的字符串 id 的构成,你应该可以明白。

思考: 这种方式的 ResultMap 默认是强绑在一个 @TableName 上的,如果是某个聚合查询或者查询的结果并非对应一个真实的表怎么办呢?有没有更优雅的方式?

基于上面的思考,我做了下面简单的实现:

关键代码其实没有几行,耐心看下应该不难懂。

还是用例子来说明更直观。

下面是一个聚合查询:

其中 BookAgg 的定义如下,在实体类上使用了 @AutoResultMap 注解: