【原创】Kotlin使用Lambda形式的QueryWrapper进行查询,解决SpringBoot中Kotlin无法使用LambdaQueryWrapper执行查询的问题

文章讲述了在Kotlin中使用LambdaQueryWrapper遇到的问题,提出两种解决方案:自定义KQueryWrapper类通过反射获取字段名,以及利用MybatisPlus的KtQueryWrapper但其对JavaBean的限制。作者强调了各自优缺点。

前言

众所周知,Kotlin无法使用LambdaQueryWrapper进行查询,会无法找到相关Lambda表达式的方法,导致报错,这就导致Kotlin因为这么一个小问题变得不香了,当然这个问题也很好解决。

报错如下:

代码如下:

        val lambdaQueryWrapper = LambdaQueryWrapper<ExampleEntity>()
        lambdaQueryWrapper.like(ExampleEntity::name,  qo.name)
        lambdaQueryWrapper.gt(ExampleEntity::number, qo.number)
        val selectList1 = exampleMapper.selectList(lambdaQueryWrapper)
        logInfo("selectList1 is ${selectList1.toJson()}")

网上已经有很多说明为什么会报错的文章了,我这就不再赘述了

解决方案1:手撸一个查询类

不就是通过方法名获取字段名吗,我自己写一个转换类不就行了!反射走起!

直接上代码:

package com.itdct.server.system.dict

import cn.hutool.core.util.StrUtil
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
import com.itdct.server.common.util.log.logInfo
import com.itdct.server.system.dict.entity.SysDictEntity
import kotlin.reflect.KFunction

/**
 * @author DCT
 * @date 2023/10/23 18:05:39
 * @version 1.0
 * @description
 */

class KQueryWrapper<T> : QueryWrapper<T>() {

    fun eq(function: KFunction<Any>, value: Any?, ignoreIfNull: Boolean = true): KQueryWrapper<T> {
        value?.also {
            eq(getTableFieldName(function), value)
        } ?: also {
            if (!ignoreIfNull) {
                eq(getTableFieldName(function), value)
            }
        }
        return this
    }

    fun like(function: KFunction<Any>, value: Any?, ignoreIfNull: Boolean = true): KQueryWrapper<T> {
        value?.also {
            like(getTableFieldName(function), value)
        } ?: also {
            if (!ignoreIfNull) {
                like(getTableFieldName(function), value)
            }
        }
        return this
    }

    fun notLike(function: KFunction<Any>, value: Any?, ignoreIfNull: Boolean = true): KQueryWrapper<T> {
        value?.also {
            notLike(getTableFieldName(function), value)
        } ?: also {
            if (!ignoreIfNull) {
                notLike(getTableFieldName(function), value)
            }
        }
        return this
    }

    fun ne(function: KFunction<Any>, value: Any?, ignoreIfNull: Boolean = true): KQueryWrapper<T> {
        value?.also {
            ne(getTableFieldName(function), value)
        } ?: also {
            if (!ignoreIfNull) {
                ne(getTableFieldName(function), value)
            }
        }
        return this
    }

    fun gt(function: KFunction<Any>, value: Any?, ignoreIfNull: Boolean = true): KQueryWrapper<T> {
        value?.also {
            gt(getTableFieldName(function), value)
        } ?: also {
            if (!ignoreIfNull) {
                gt(getTableFieldName(function), value)
            }
        }
        return this
    }

    fun lt(function: KFunction<Any>, value: Any?, ignoreIfNull: Boolean = true): KQueryWrapper<T> {
        value?.also {
            lt(getTableFieldName(function), value)
        } ?: also {
            if (!ignoreIfNull) {
                lt(getTableFieldName(function), value)
            }
        }
        return this
    }

    fun between(function: KFunction<Any>, left: Any?, right: Any?): KQueryWrapper<T> {
        if (left == null || right == null) {
            return this
        }
        between(getTableFieldName(function), left, right)
        return this
    }

    fun notBetween(function: KFunction<Any>, left: Any?, right: Any?): KQueryWrapper<T> {
        if (left == null || right == null) {
            return this
        }
        notBetween(getTableFieldName(function), left, right)
        return this
    }

    fun isNull(function: KFunction<Any>): KQueryWrapper<T> {
        isNull(getTableFieldName(function))
        return this
    }

    fun isNotNull(function: KFunction<Any>): KQueryWrapper<T> {
        isNotNull(getTableFieldName(function))
        return this
    }

    fun getTableFieldName(function: KFunction<Any>): String {
        val functionName = function.name
        var prefixLength = 0
        if (functionName.startsWith("get") || functionName.startsWith("set")) {
            prefixLength = 3
        } else if (functionName.startsWith("is")) {
            prefixLength = 2
        }
        var tableFieldName = ""

        if (prefixLength != 0) {
            var fieldName = functionName.substring(prefixLength)
            fieldName = fieldName.substring(0, 1).lowercase() + fieldName.substring(1)
//            val declaredField = clazz.getDeclaredField(fieldName)
//            val tableField = declaredField.getAnnotation(TableField::class.java)
//            if (tableField != null) {
//                // INFO: DCT: 2023/10/24 存在tableField注解,则使用tableField注解中的内容
//                tableFieldName = tableField.value
//            } else {
            tableFieldName = StrUtil.toUnderlineCase(fieldName)
//            }
            logInfo("tableFieldName is $tableFieldName")
            return tableFieldName
        } else {
            return tableFieldName
        }
    }

}

fun main() {
    val kQueryWrapper = KQueryWrapper<SysDictEntity>()
    kQueryWrapper.eq(SysDictEntity::getRemark, 15).eq(SysDictEntity::getParentId, 12)
}

入参为KFunction也就是Kotlin的方法,就通过方法名去解析出数据库的字段名就行了,本来还想加TableField注解去转换,后来想想反射比较消耗性能,索性不加更好,要用TableField就直接写字段名吧。

这个方法还有一个好处,如果为空,能不加上这个查询,省得再手动判断了。当然继承自QueryWrapper,它自带的方法也是可以用的。

使用例子如下:

        val kQueryWrapper = KQueryWrapper<ExampleEntity>()
        kQueryWrapper.like(ExampleEntity::getName, qo.name)
            .gt(ExampleEntity::getNumber, qo.number)
        val selectList = exampleMapper.selectList(kQueryWrapper)

解决方案2:MP自带

当我撸完上面这段代码后,发现MybatisPlus居然自带一个KtQueryWrapper,这把我气得,原来MP自己就有,我的时间都浪费了,不过这个自带的有个问题,它的入参是KProperty,也就是成员变量,关键是这个类必须是KotlinBean,不能是JavaBean,这就带来了一些局限,如果这个类是别人Java写好的实体类,这玩意就用不了了,而我的解决方案1没有这个顾虑,因为传入的是方法。

查询写法如下:

        val ktQueryWrapper = KtQueryWrapper(ExampleEntity::class.java)
        ktQueryWrapper.like(ExampleEntity::name, qo.name)
            .gt(ExampleEntity::number, qo.number)
        val selectList2 = exampleMapper.selectList(ktQueryWrapper)

好处是起来更省事,不用再加get了,直接使用成员变量名即可,看看源码实在是太优雅了,不得不说MP作者还是强啊。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值