Lecture06-条件构造器[二]-LambdaQueryWrapper

文章目录

    [toc]

    单词词性音标含义
    Lambdan./ˈlæmdə/希腊字母 λ(Java 8 引入的函数式写法,LambdaQueryWrapper 用 Employee::getEmpName 这种形式引用属性)
    Referencen./ˈrefrəns/引用(Employee::getEmpName 是方法引用,指向实体类的 getter 方法)
    And / Orconj./ænd/ /ɔː(r)/与 / 或(条件之间用 and、or 组合,形成嵌套逻辑)

    Lecture06-条件构造器[二]-LambdaQueryWrapper

    一、QueryWrapper 的缺点

    上一章 QueryWrapper 里,列名是手写字符串:

    wrapper.eq("dept_id", 1)
           .like("emp_name", "张");
    

    它的两个痛点:

    1. 写错不报错:"dept_id" 写成 "deptId"、"emp_name" 写成 "empName",编译期毫无察觉,运行时才报 SQL 错误
    2. 重构不安全:数据库列名改了,字符串不会跟着变,全靠肉眼找

    二、LambdaQueryWrapper 是什么

    LambdaQueryWrapper 是 QueryWrapper 的升级版,列名改用方法引用(Employee::getEmpName)来表示:

    需要导入:import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

    LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
    
    wrapper.eq(Employee::getDeptId, 1)          // 属性 empId 对应列 emp_id,框架自动转换
           .like(Employee::getEmpName, "张")
           .orderByDesc(Employee::getEmpSalary);
    
    List<Employee> employeeList = employeeMapper.selectList(wrapper);
    

    生成的 SQL 和上一章完全一样:

    ==>  Preparing: SELECT ... FROM t_emp WHERE dept_id=? AND emp_name LIKE ? ORDER BY emp_salary DESC
    

    好处:

    • 属性名 getEmpName 写错,编译期直接报错,或者说有提示的情况下很难写错
    • 实体属性重命名,这里必须跟着变,重构安全
    • 不用记数据库列名,IDE 有自动补全

    三、两种写法对比

    对比项QueryWrapperLambdaQueryWrapper
    列名写法字符串 "emp_name"方法引用 Employee::getEmpName
    写错列名编译期不报错,运行时报错编译期直接报错
    重构安全性差好
    IDE 提示无有自动补全
    推荐度了解即可推荐使用

    常用方法名完全一样:eq / ne / gt / ge / lt / le / between / in / like / isNull / orderByDesc / groupBy / select 等,只是第一个参数从字符串换成方法引用。

    注意:select 方法传方法引用时略有不同(见下文示例 2)。


    四、创建 LambdaQueryWrapper 的三种方式

    // 方式一:直接 new(最常用)
    LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
    
    // 方式二:通过 Wrappers 工具类
    LambdaQueryWrapper<Employee> wrapper2 = Wrappers.lambdaQuery();
    
    // 方式三:QueryWrapper 转 Lambda(已有 QueryWrapper 时)
    QueryWrapper<Employee> old = new QueryWrapper<>();
    LambdaQueryWrapper<Employee> wrapper3 = old.lambda();
    

    五、and / or:组合复杂逻辑

    多个条件默认用 AND 连接。需要 OR 时显式调用 or():

    示例 1:简单 OR

    // 查询:部门 1 的员工,或者工资大于 10000 的员工
    LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(Employee::getDeptId, 1)
           .or()
           .gt(Employee::getEmpSalary, 10000);
    
    ==>  Preparing: SELECT ... FROM t_emp WHERE dept_id=? OR emp_salary > ?
    

    示例 2:括号嵌套 (A OR B) AND C

    直接 or() 会把整条链路打平,但实际需求常是「(部门1 或 工资>10000) 且 姓名包含张」。此时用 嵌套 and/or:

    LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
    wrapper.and(w -> w.eq(Employee::getDeptId, 1)
                      .or()
                      .gt(Employee::getEmpSalary, 10000))   // 括号 (A OR B)
           .like(Employee::getEmpName, "张");               // AND C
    
    ==>  Preparing: SELECT ... FROM t_emp WHERE (dept_id=? OR emp_salary > ?) AND emp_name LIKE ?
    

    要点:

    • and(w -> ...) 表示在括号里面条件的前面加 AND and() 方法本身的参数是一个消费型的函数式接口,Lambda 表达式的入参就是前面创建的 LambdaQueryWrapper 对象 Lambda 体中拿到 LambdaQueryWrapper 对象就根据需要拼接条件就行了,它们最终会被放在括号中
    • or(w -> ...) 表示在括号里面条件的前面加 OR or() 方法本身的参数是一个消费型的函数式接口,Lambda 表达式的入参就是前面创建的 LambdaQueryWrapper 对象 Lambda 体中拿到 LambdaQueryWrapper 对象就根据需要拼接条件就行了,它们最终会被放在括号中
    • 括号里的条件可以继续任意嵌套

    示例 3:or 中带 and 嵌套

    // 查询:工资>10000 的员工,或者(部门1 且 姓名含张)的员工
    wrapper.gt(Employee::getEmpSalary, 10000)
           .or(w -> w.eq(Employee::getDeptId, 1)
                      .eq(Employee::getEmpName, "张"));
    

    六、实验:员工多条件搜索

    需求

    根据前端传来的条件搜索员工,条件是"可选"的:

    • 姓名:模糊匹配
    • 部门:精确匹配
    • 工资下限 / 上限:区间匹配

    代码

    @Test
    public void testSearch() {
        // 模拟前端传来的条件(实际开发中这些值来自 Controller 参数)
        String name = "张";          // 可能为 null:不限制姓名
        Integer deptId = null;       // 可能为 null:不限制部门
        BigDecimal minSalary = new BigDecimal("6000");
        BigDecimal maxSalary = null; // 可能为 null:不限制上限
    
        LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
        // 第一个 boolean 参数为 false 时,该条件整条被忽略 —— 天然支持可选条件
        wrapper.like(name != null, Employee::getEmpName, name)
               .eq(deptId != null, Employee::getDeptId, deptId)
               .ge(minSalary != null, Employee::getEmpSalary, minSalary)
               .le(maxSalary != null, Employee::getEmpSalary, maxSalary)
               .orderByDesc(Employee::getEmpSalary);
    
        List<Employee> employeeList = employeeMapper.selectList(wrapper);
        employeeList.forEach(System.out::println);
    }
    

    重点:eq(boolean condition, ...) 这类重载,第一个 boolean 参数为 false 时整条条件被忽略。这就是动态查询的标配写法,工作中每天都在用。


    七、本章小结

    • 推荐使用 LambdaQueryWrapper:列名用方法引用,编译期检查,重构安全
    • 创建方式:new LambdaQueryWrapper<>() 或 Wrappers.lambdaQuery()
    • 嵌套逻辑:and(w -> ...) / or(w -> ...) 加括号,实现 (A OR B) AND C
    • 可选条件:eq(boolean, 列, 值) 第一个参数控制条件是否生效
    • 与 QueryWrapper 方法名通用,学会一个另一个就会了

    下一章学习分页查询。

    end