使用MyBatisPlus的自定义SQL方法时遇到的一些问题

在MyBatisPlus的使用过程中,之前很多时候都是使用queryWrapper(条件构造器)的构造方法传入实体对象,来实现条件的构造,例如

contentCategoryService.list(new QueryWrapper<ContentCategory>(contentCategory))

这个方法里是这么写的,原先我以为构造这里会去利用entity构造一个MP的条件对象,直到我用了自定义sql的方法。

public QueryWrapper(T entity) {
    super.setEntity(entity);
    super.initNeed();
}

MP 是支持自定义sql的,官方文档用法如下:
file

看demo的理解就是MP会帮助你拼接wrapper中构造的条件,利用 ew.customSqlSegment 注入到sql中去,但是在实际使用中发现,只有调用条件构造方法(例如 eq like ne 等方法)才能顺利的拼接到SQL中去,这个着实让不少人踩了坑(并没有诋毁和不尊重开源团队的意思),因为这个文档也是在2020年才补上去的 😀

https://github.com/baomidou/mybatis-plus/issues/3151 (有问题就查github issues)

%title插图%num

后来发现发现了文档上的另外一句话,一开始并没有很理解 注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行 这句话,直到去看了自定义SQL中的 getCustomSqlSegment 方法

file

/**
 * 获取自定义SQL 简化自定义XML复杂情况
 * <p>使用方法</p>
 * <p>`自定义sql` + ${ew.customSqlSegment}</p>
 * <p>1.逻辑删除需要自己拼接条件 (之前自定义也同样)</p>
 * <p>2.不支持wrapper中附带实体的情况 (wrapper自带实体会更麻烦)</p>
 * <p>3.用法 ${ew.customSqlSegment} (不需要where标签包裹,切记!)</p>
 * <p>4.ew是wrapper定义别名,可自行替换</p>
 */
public String getCustomSqlSegment() {
    MergeSegments expression = getExpression();
    if (Objects.nonNull(expression)) {
        NormalSegmentList normal = expression.getNormal();
        String sqlSegment = getSqlSegment();
        if (StringUtils.isNotEmpty(sqlSegment)) {
            if (normal.isEmpty()) {
                return sqlSegment;
            } else {
                return Constants.WHERE + StringPool.SPACE + sqlSegment;
            }
        }
    }
    return StringPool.EMPTY;
}

这个方法注释里也写清楚了不支持wrapper中的entity对象,看来我理解错了。所以我就单独去设置了条件和entity构造,去试一下最终生成的语句

//构造方法,传入entity,GenericQueryWrapper是我继承AbstractWrapper的实现类,和QueryWrapper差不多
//此时facility中有个facilityName,前台会传递过来一个值“氪空间”
GenericQueryWrapper wrapper = new GenericQueryWrapper<Facility>(facility);

//在手动设定一个相同的字段
wrapper.eq("facilityName","仓库");

//看下最终生成的 SQL
return getDataTable(facilityService.list(wrapper));

执行之后,生成的语句是这样的,所以现在有点理解那句话的含义了,wrapper中的条件方法和entity的处理方法是不一样的,并且相同字段也不会覆盖,所以是没有任何关联

==>  Preparing: SELECT count(0) FROM facility WHERE facility_name = ? AND (facility_name = ?) 

==> Parameters: 氪空间(String), 仓库(String)

问题找到了,那么就看怎么解决,有2种方法,一种是老老实实用wrapper自己的方法 eq ne like 这种,另外就是自己实现 eq.customeSqlSegment 方法,叫什么无所谓,实现方式就是类似的。后来发现一个老哥的另外一种思路,就是通过entity生成对应的wrapper,也不失为一种办法。https://juejin.cn/post/7000732375629955080

在解决这个问题的过程中,我一直在找MP baseMapper 自带的方法(selectList selectById等)是怎么利用entity生成条件的,根据文档中的指引,可以看到是通过SQL注入器来做的,但是并没有找到利用wrapper和wrapper中的entity生成条件的相关代码

向所有开源项目维护和贡献者致敬!

站内相关文章:

Comment ()
如果您有不同的看法,或者疑问,欢迎指教