【1】MyBatis Plus中的嵌套查询
很多时候我们可能需要构造一个嵌套查询,如WHERE (name = ? AND ( (id = ? OR type = ?) ))。外层是and(or)连接,嵌套一个or(and)查询。MyBatis Plus同样对此提供了支持,在Nested<Param, Children>接口中我们可以看到具体使用方法。
① Nested<Param, Children>接口源码
public interface Nested<Param, Children> extends Serializable { //jdk1.8中支持了default方法,如下是and嵌套 default Children and(Consumer<Param> consumer) { return this.and(true, consumer); } //带条件的and嵌套 Children and(boolean condition, Consumer<Param> consumer); //or嵌套 default Children or(Consumer<Param> consumer) { return this.or(true, consumer); } //带条件的or嵌套 Children or(boolean condition, Consumer<Param> consumer); //不带and or的普通嵌套 default Children nested(Consumer<Param> consumer) { return this.nested(true, consumer); } //不带条件的不带and or的普通嵌套 Children nested(boolean condition, Consumer<Param> consumer); }
那么如何使用呢?这里建议有lambda表达式基础。
② 嵌套应用实例
如我们要达到的SQL效果为:WHERE (name = ? AND ( (id = ? OR type = ?) ))
第一种写法
这种写法比较麻烦,相当于实现了一个匿名类。
QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>(); queryWrapper.eq("name","jane"); queryWrapper.and(new Consumer<QueryWrapper<SysUser>>() { @Override public void accept(QueryWrapper<SysUser> sysUserQueryWrapper) { sysUserQueryWrapper.eq("id",1).or().eq("type",0); } });
第二种写法使用lambda表达式
QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>(); queryWrapper.eq("name","jane"); queryWrapper.and(e-> e.eq("id",1).or().eq("type",0));
这种确实很简洁了。
但是是用and嵌套需要注意的是and里面的查询条件不能为空,否则将会查询不到数据。示例如下:
queryWrapper.eq(categoryId!=null,"category_id",categoryId); queryWrapper.and(e->e.like(!StringUtils.isEmpty(vagueParam),"title",vagueParam).or() .like(!StringUtils.isEmpty(vagueParam),"theme",vagueParam));
当categoryId存在但是vagueParam为空的时候解析后的SQL如下所示:
where category_id=1 and (null)
这时是查询不到数据的,而MBP(MyBatis Plus)没有规避这种问题,故而需要程序员自行规避这个问题。
如果or里面有and呢?比如下面这个avg_price
WHERE ( field0 IN (?,?,?)and AND ( ( avg_price <= ? OR ( ( avg_price <= ? AND avg_price >= ? ) ) OR ( ( avg_price <= ? AND avg_price >= ? ) ) ) ) )
这时我们采用Children or(Consumer<Param> consumer)
方法:
// 人均费用 if(!StringUtils.isEmpty(totalPrice)){ queryWrapper.and( e->{ if(totalPrice.contains("999")){ e.le("avg_price",999).or(); } if(totalPrice.contains("2999")){ e.or(e1->e1.le("avg_price",2999).ge("avg_price",1000)).or(); } } ); } default Children or(Consumer<Param> consumer) { return or(true, consumer); }
【2】UpdateWrapper
更新时候使用。
① update(Wrapper<T> updateWrapper
)
这里以eq…set为例说明,eq作为更新条件,set为字段赋值。实例代码如下:
UpdateWrapper<SysOrderItem> updateWrapper=new UpdateWrapper(); updateWrapper.eq("order_id",1).set("state",1); orderItemService.update(updateWrapper);
SQL如下:
UPDATE yihuiyuan.tb_sys_order_item SET state=? WHERE (order_id = ?)
② update(T entity, Wrapper<T>
updateWrapper)
前面entity都被封装为set属性,后面的updateWrapper则如①一样被正常解析。
实例代码如下:
UpdateWrapper<SysOrderItem> updateWrapper=new UpdateWrapper(); updateWrapper.eq("order_id",1).set("state",1); SysOrderItem sysOrderItem=new SysOrderItem(); sysOrderItem.setNumber(10); orderItemService.update(sysOrderItem,updateWrapper);
SQL如下:
UPDATE tb_sys_order_item SET number=?, state=? WHERE (order_id = ?)
这里需要注意的是如果entity里面有字段和updateWrapper中set字段一样,则会出现重复,这时SQL执行效果为以后面的state为主:
UpdateWrapper<SysOrderItem> updateWrapper=new UpdateWrapper(); updateWrapper.eq("order_id",1).set("state",1); SysOrderItem sysOrderItem=new SysOrderItem(); sysOrderItem.setNumber(10); //如下也设置state属性 sysOrderItem.setState(10); orderItemService.update(sysOrderItem,updateWrapper);
SQL如下:
UPDATE tb_sys_order_item SET number=?, state=?, state=? WHERE (order_id = ?)