在MyBatisPlus的使用过程中,之前很多时候都是使用queryWrapper(条件构造器)的构造方法传入实体对象,来实现条件的构造,例如
contentCategoryService.list(new QueryWrapper<ContentCategory>(contentCategory))
这个方法里是这么写的,原先我以为构造这里会去利用entity构造一个MP的条件对象,直到我用了自定义sql的方法。
public QueryWrapper(T entity) {
super.setEntity(entity);
super.initNeed();
}
MP 是支持自定义sql的,官方文档用法如下:
看demo的理解就是MP会帮助你拼接wrapper中构造的条件,利用 ew.customSqlSegment
注入到sql中去,但是在实际使用中发现,只有调用条件构造
方法(例如 eq like ne 等方法)才能顺利的拼接到SQL中去,这个着实让不少人踩了坑(并没有诋毁和不尊重开源团队的意思),因为这个文档也是在2020年才补上去的 😀
https://github.com/baomidou/mybatis-plus/issues/3151 (有问题就查github issues)
后来发现发现了文档上的另外一句话,一开始并没有很理解 注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行
这句话,直到去看了自定义SQL中的 getCustomSqlSegment 方法
/**
* 获取自定义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生成条件的相关代码
向所有开源项目维护和贡献者致敬!