阅读 1741

mybatis-plus 自定义QueryWrapper(一)实现查询函数

前言

以下所有代码和观点来源均为

        <dependency>             <groupId>org.mybatis.spring.boot</groupId>             <artifactId>mybatis-spring-boot-starter</artifactId>             <version>2.0.1</version>         </dependency> 复制代码

mybatis-plus 作为一个强大的 mybatis阵营的orm框架,很多功能已经用的飞起,但是呢在查询方面还是欠缺部分api,比如要进行如下查询时无法用到 lamdba表达式

    select min(column) as n from table  复制代码

这时候是无法用自带的LambdaQueryWrapper实现的,此时就需要我们手动改造下

分析源码

核心源码其实就两个方法一个属性

 // 存放sql语句 private SharedString sqlSelect = new SharedString(); @SafeVarargs @Override public final LambdaQueryWrapper<T> select(SFunction<T, ?>... columns) {     if (ArrayUtils.isNotEmpty(columns)) {         this.sqlSelect.setStringValue(columnsToString(false, columns));     }     return typedThis; } @Override public String getSqlSelect() {     return sqlSelect.getStringValue(); } 复制代码

SharedString 这个类本质上也是一个string只是多了几个方法而已

public class SharedString implements Serializable {     private static final long serialVersionUID = -1536422416594422874L;     /**      * 共享的 string 值      */     private String stringValue;     /**      * SharedString 里是 ""      */     public static SharedString emptyString() {         return new SharedString(StringPool.EMPTY);     }     /**      * 置 empty      *      * @since 3.3.1      */     public void toEmpty() {         stringValue = StringPool.EMPTY;     }     /**      * 置 null      *      * @since 3.3.1      */     public void toNull() {         stringValue = null;     } } 复制代码

所以在使用中多个字段的查询不能函数调用

改造

此时我们自己实现 LambdaQueryWrapper,然后将SharedString 改成一个由list实现的类

自定义的LambdaQueryWrapper 命名为 MyLambdaQueryWrapper

public class MyLambdaQueryWrapper<T> extends AbstractLambdaWrapper<T, MyLambdaQueryWrapper<T>>         implements Query<MyLambdaQueryWrapper<T>, T, SFunction<T, ?>> {     private SelectBuilder sqlSelect = new SelectBuilder();     /**      * 不建议直接 new 该实例,使用 Wrappers.lambdaQuery(entity)      */     public MyLambdaQueryWrapper() {         this((T) null);     }     /**      * 不建议直接 new 该实例,使用 Wrappers.lambdaQuery(entity)      */     public MyLambdaQueryWrapper(T entity) {         super.setEntity(entity);         super.initNeed();     }     /**      * 不建议直接 new 该实例,使用 Wrappers.lambdaQuery(entity)      */     public MyLambdaQueryWrapper(Class<T> entityClass) {         super.setEntityClass(entityClass);         super.initNeed();     }     /**      * 不建议直接 new 该实例,使用 Wrappers.lambdaQuery(...)      */     MyLambdaQueryWrapper(T entity, Class<T> entityClass, SelectBuilder sqlSelect, AtomicInteger paramNameSeq,                        Map<String, Object> paramNameValuePairs, MergeSegments mergeSegments,                        SharedString lastSql, SharedString sqlComment, SharedString sqlFirst) {         super.setEntity(entity);         super.setEntityClass(entityClass);         this.paramNameSeq = paramNameSeq;         this.paramNameValuePairs = paramNameValuePairs;         this.expression = mergeSegments;         this.sqlSelect = sqlSelect;         this.lastSql = lastSql;         this.sqlComment = sqlComment;         this.sqlFirst = sqlFirst;     }     /**      * SELECT 部分 SQL 设置      *      * @param columns 查询字段      */     @SafeVarargs     @Override     public final MyLambdaQueryWrapper<T> select(SFunction<T, ?>... columns) {         if (ArrayUtils.isNotEmpty(columns)) {             this.sqlSelect.getParts().add(columnsToString(columns));         }         return typedThis;     }     /**      * 过滤查询的字段信息(主键除外!)      * <p>例1: 只要 java 字段名以 "test" 开头的             -> select(i -&gt; i.getProperty().startsWith("test"))</p>      * <p>例2: 只要 java 字段属性是 CharSequence 类型的     -> select(TableFieldInfo::isCharSequence)</p>      * <p>例3: 只要 java 字段没有填充策略的                 -> select(i -&gt; i.getFieldFill() == FieldFill.DEFAULT)</p>      * <p>例4: 要全部字段                                   -> select(i -&gt; true)</p>      * <p>例5: 只要主键字段                                 -> select(i -&gt; false)</p>      *      * @param predicate 过滤方式      * @return this      */     @Override     public MyLambdaQueryWrapper<T> select(Class<T> entityClass, Predicate<TableFieldInfo> predicate) {         if (entityClass == null) {             entityClass = getEntityClass();         } else {             setEntityClass(entityClass);         }         Assert.notNull(entityClass, "entityClass can not be null");         this.sqlSelect.getParts().add(TableInfoHelper.getTableInfo(entityClass).chooseSelect(predicate));         return typedThis;     }     @Override     public String getSqlSelect() {         return sqlSelect.getStringValue();     }     /**      * 用于生成嵌套 sql      * <p>故 sqlSelect 不向下传递</p>      */     @Override     protected MyLambdaQueryWrapper<T> instance() {         return new MyLambdaQueryWrapper<>(getEntity(), getEntityClass(), null, paramNameSeq, paramNameValuePairs,                 new MergeSegments(), SharedString.emptyString(), SharedString.emptyString(), SharedString.emptyString());     }     @Override     public void clear() {         super.clear();         sqlSelect.toNull();     } // =================== 上面的代码都是照抄的   =====================     public MyLambdaQueryWrapper<T> min(SFunction<T, ?> column){         if (column != null) {             this.sqlSelect.getParts().add(String.format("min(%s)", columnToString(column)));         }         return typedThis;     }     public MyLambdaQueryWrapper<T> max(SFunction<T, ?> column){         if (column != null) {             this.sqlSelect.getParts().add(String.format("max(%s)", columnToString(column)));         }         return typedThis;     }     public MyLambdaQueryWrapper<T> sum(SFunction<T, ?> column){         if (column != null) {             this.sqlSelect.getParts().add(String.format("sum(%s)", columnToString(column)));         }         return typedThis;     }     public MyLambdaQueryWrapper<T> as(String asName){         if (StringUtils.isEmpty(asName)) {             return typedThis;         }         List<String> parts = this.sqlSelect.getParts();         if (CollectionUtil.isEmpty(parts)) {             return typedThis;         }         String lastPart = parts.remove(parts.size() - 1);         lastPart += " as " + asName;         parts.add(lastPart);         return typedThis;     } } 复制代码

还有一个暂存查询列的list组装对象

@Getter @Setter public class SelectBuilder implements Serializable {     private static final long serialVersionUID = -1536422416594422874L;     private List<String> parts;     public SelectBuilder() {         this.parts = new ArrayList<>();     }     public void toEmpty() {         parts.clear();     }     /**      * 置 null      *      * @since 3.3.1      */     public void toNull() {         parts = null;     }     public String getStringValue(){         if (CollectionUtil.isNotEmpty(parts)) {             return String.join(",", parts);         }else {             return null;         }     } } 复制代码

使用代码

MyLambdaQueryWrapper<SignConfig> myLambdaQuery = getMyLambdaQuery(); myLambdaQuery.min(SignConfig::getLongitude).as("logg"); myLambdaQuery.sum(SignConfig::getLongitude).as("lo"); return baseMapper.selectObjs(myLambdaQuery); 复制代码

对应的sql

SELECT min(longitude) as logg,sum(longitude) as lo FROM work_sign_config


作者:帆影匆匆ig
链接:https://juejin.cn/post/7018464189869981732


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐