Mybatis 注解形式多条件查询

本文介绍了一个基于MyBatis的商家信息实体类定义及多条件查询接口实现,包括使用SelectProvider注解进行灵活的SQL拼接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建商家实体类

package com.clsystem.Dto;

import com.clsystem.MybatisUtil.Invisible;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.List;

/**
 * Created by pudding on 2017-10-25.(YYR)(商家信息)
 */
@Data
@ApiModel("Shop(商家模型)")
public class Shop {

    @ApiModelProperty("id")
    Integer id;

    @ApiModelProperty("所属业务员Id")
    Integer user_id;//所属业务员Id

    @ApiModelProperty("店铺名称")
    String shop_name;//店铺名称

    @ApiModelProperty("店铺面积")
    String area;//店铺面积

    @ApiModelProperty("固定电话")
    String  telephone;//固定电话

    @ApiModelProperty("手机号")
    String phone;//手机号

    @ApiModelProperty("经营类别(可以有多个类别)")
    @Invisible
    List<ShopBusiness> shopBusinessList;//经营类别

    @ApiModelProperty("店铺地区")
    String shop_address;//店铺地区

    @ApiModelProperty("详细地址")
    String detailed_address;//详细地址

    @ApiModelProperty("级别")
    String  level;//级别

    @ApiModelProperty("状态")
    String status;//状态

    @ApiModelProperty("备注")
    String remarks;//备注

    @ApiModelProperty("公司名称")
    String corporate_name;//公司名称

    @ApiModelProperty("法人姓名")
    String LegalPerson_name;//法人姓名

    @ApiModelProperty("法人电话")
    String LegalPerson_phone;//法人电话

    @ApiModelProperty("经办人姓名")
    String operator_name;//经办人姓名

    @ApiModelProperty("经办人电话")
    String operator_phone;//经办人电话

    @ApiModelProperty("负责人姓名")
    String charge_name;//负责人姓名

    @ApiModelProperty("负责人电话")
    String charge_phone;//负责人电话

    @ApiModelProperty("集团/公司电话")
    String corporate_phone;//集团/公司电话

}

创建mapper接口 使用SelectProvider注解(实现通过用户ID,级别,状态多条件查询)

package com.clsystem.Mapper;

import com.clsystem.Dto.Shop;
import com.clsystem.Mapper.Provider.ShopProvider;
import com.clsystem.MybatisUtil.SimpleInsertLangDriver;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * Created by pudding on 2017-10-25.(YYR)
 */
@Mapper
@Component
public interface ShopMapper {

    /**
     * 通过userId和level,status查询商家信息不分页 (我负责的)
     * @param userId
     * @return
     */
    @SelectProvider(type = ShopProvider.class,method = "findShopByLevelAndStatus")//多条件关键注释
    @Results({@Result(property = "id", column = "id"),@Result(property =   "shopBusinessList", javaType = List.class, column = "id",many = @Many(select = "com.clsystem.Mapper.ShopBusinessMapper.findBusinessByShopId"))})
    List<Shop> findShopByLevelAndStatus(Integer userId,String level,String status);

}

实现多条件查询创建ShopProvider类

package com.clsystem.Mapper.Provider;

/**
 * Created by pudding on 2017-11-20.
 */
public class ShopProvider {

    /**
     * 通过重要程度和状态查询商家
     * @param userId
     * @param level
     * @param status
     * @return
     */
    public String findShopByLevelAndStatus(Integer userId,String level,String status){

        StringBuffer sql=new StringBuffer("select * from cl_shop  where user_id="+userId+" ");

        if (!level.equals("")){
            sql.append(" and level='"+level+"' ");
        }

        if (!status.equals("")){
            sql.append(" and status='"+status+"' ");
        }

        sql.append("order by id desc");

        return sql.toString();
    }
}

—————————————–最后使用Service,Controller 调用接口,让我们调用接口来试试吧!———————————

这里写图片描述

——————————————查询结果,到这里就实现了mybatis注解方式的多条件查询!—————————————

这里写图片描述

<think>我们正在讨论的是MyBatis Plus中LambdaQueryWrapper在多表查询时如何使用其他表的字段作为查询条件。在单表查询中,LambdaQueryWrapper非常方便,因为它可以通过方法引用来避免硬编码字段名。但在多表查询时,我们需要考虑如何关联其他表并引用其他表的字段。 根据引用[1],LambdaQueryWrapper和QueryWrapper都是MyBatis Plus的查询条件封装类,其中LambdaQueryWrapper使用Lambda表达式,而QueryWrapper使用字符串。LambdaQueryWrapper的优点在于编译时类型安全和避免字段名拼写错误,但在多表查询中,它默认只能处理当前实体对应的表。 那么,如何实现多表查询条件呢?我们可以通过以下两种主要方式: 1. **使用JOIN语句(手动编写SQL)并配合条件构造器**:这种方式下,我们可以使用QueryWrapper或LambdaQueryWrapper来构建条件,但需要自己编写JOIN语句,并且为其他表的字段设置别名,然后在条件中使用这些别名。 2. **使用MyBatis Plus的联表查询功能(如@TableField注解的one和many属性)**:这种方式适用于定义好的实体关系,可以通过关联关系自动查询。但是,这种方式在条件构造上可能不够灵活。 然而,LambdaQueryWrapper本身并不直接支持跨表条件,所以我们需要结合其他方式。下面介绍两种常见方法: ### 方法一:使用QueryWrapper并手动指定表别名(字符串方式) 我们可以使用QueryWrapper,通过字符串指定表别名和字段名: ```java QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.select("u.*, o.order_no") .from("user u") .leftJoin("order o ON u.id = o.user_id") .eq("o.status", 1); // 这里使用订单表的status字段作为条件 ``` 但是这种方式不是类型安全的,且容易出错。 ### 方法二:使用LambdaQueryWrapper结合自定义SQL(推荐) 我们可以利用LambdaQueryWrapper来构建条件,然后通过自定义SQL语句实现多表关联。具体步骤: 1. 在Mapper接口中定义自定义查询方法,使用@Select注解或XML映射文件编写SQL。 2. 在SQL中,我们使用JOIN关联多个表,并为同名字段设置别名以避免冲突。 3. 在条件部分,我们可以使用LambdaQueryWrapper来构建条件,但注意,LambdaQueryWrapper只能构建当前实体对应的表条件。对于其他表,我们需要在SQL中显式写出条件,或者将条件值传入到自定义方法中,然后在SQL中使用。 然而,LambdaQueryWrapper并不能直接用于多表条件。因此,我们可以这样做: 在自定义SQL中,我们使用参数传递条件值,然后在SQL中写条件。 但是,如果我们希望构建一个统一的条件构造器,我们可以使用MyBatis Plus的`join`方法(在3.4.0版本以上支持)?实际上,官方文档中并没有提供LambdaQueryWrapper直接跨表的功能。所以,我们可能需要使用字符串方式,或者采用以下方式: ### 方法三:使用MyBatis Plus的JoinLambdaWrapper(第三方扩展) 有一个第三方库`mybatis-plus-join`(https://github.com/yulichang/mybatis-plus-join)提供了对多表查询的支持,它扩展了LambdaQueryWrapper,支持多表条件。 示例: ```java JoinLambdaWrapper<User> wrapper = new JoinLambdaWrapper<>(User.class) .selectAll(User.class) .select(Order::getOrderNo) .leftJoin(Order.class, Order::getUserId, User::getId) .eq(Order::getStatus, 1); List<User> userList = userMapper.selectJoinList(User.class, wrapper); ``` 这种方式可以让我们使用Lambda表达式来引用其他表的字段。 但是,如果你不想引入第三方库,那么可能只能选择方法一或方法二。 鉴于MyBatis Plus本身并没有提供多表Lambda的条件构造,我们通常采用以下两种方式之一: - **方式A(纯手动SQL)**:在Mapper接口中定义方法,使用@Select注解或XML编写多表查询SQL,然后通过参数传递条件值。 - **方式B(QueryWrapper+字符串)**:使用QueryWrapper的字符串方式指定多表条件。 ### 总结 在MyBatis Plus中,使用LambdaQueryWrapper直接使用其他表的字段作为条件是不直接支持的。因此,我们通常需要: 1. 使用自定义SQL(XML或注解)完成多表查询,在SQL中处理表关联和字段别名。 2. 如果需要动态条件,可以在自定义SQL中使用MyBatis的动态SQL标签(如<if>)或者将QueryWrapper作为参数传入,然后使用`${ew.customSqlSegment}`来插入条件(注意SQL注入风险,但MyBatis Plus做了处理,通常安全)。 例如,在Mapper接口中: ```java @Select("SELECT u.*, o.order_no FROM user u LEFT JOIN order o ON u.id=o.user_id ${ew.customSqlSegment}") List<User> selectUserOrderList(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper); ``` 然后,我们可以构建一个QueryWrapper,并添加条件: ```java QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("o.status", 1); List<User> list = userMapper.selectUserOrderList(wrapper); ``` 但是,这里我们使用的是字符串形式的字段名,而且需要知道表别名(如"o.status")。 如果我们想用Lambda方式,目前MyBatis Plus原生不支持。因此,如果你坚持要用Lambda表达式,可以考虑引入第三方库`mybatis-plus-join`。 最后,根据引用[4],LambdaQueryWrapper是通过Lambda表达式的序列化机制来获取字段名的,这要求表达式必须是实体类的属性。因此,跨表的情况下,它无法直接获取其他实体类的字段名。 所以,针对你的问题,答案如下: - 原生MyBatis Plus不支持LambdaQueryWrapper跨表条件,推荐使用自定义SQL+QueryWrapper(字符串方式)或引入第三方库。 如果你使用的是MyBatis Plus 3.4.0及以上版本,官方提供了一种新的方式:使用`selectMaps`或自定义ResultMap,但仍然没有提供Lambda跨表条件。 因此,建议根据项目情况选择方案: 1. 如果条件简单,使用字符串方式。 2. 如果条件复杂且需要类型安全,引入第三方库`mybatis-plus-join`。 3. 或者,使用自定义SQL(XML)编写多表查询,这样最灵活。 下面是一个使用第三方库的示例(假设已引入依赖): ```java // 使用 mybatis-plus-join LambdaJoinWrapper<User> wrapper = JoinWrappers.lambda(User.class) .selectAll(User.class) .selectAs(Order::getOrderNo, UserDTO::getOrderNo) // 设置别名到DTO .leftJoin(Order.class, Order::getUserId, User::getId) .eq(Order::getStatus, 1); // 使用Order表的字段作为条件 List<UserDTO> list = userMapper.joinSelectList(wrapper, UserDTO.class); ``` 这样,我们就可以用Lambda表达式引用其他表的字段了。 希望这能解决你的问题。</think>在 MyBatis Plus 中,使用 `LambdaQueryWrapper` 进行多表查询并引用其他表的字段作为条件,需要通过 **JOIN 操作** 和 **表别名** 来实现。以下是具体解决方案: --- ### 解决方案:JOIN 操作 + 表别名 #### 步骤 1:定义关联查询(Mapper 层) ```java @Select("SELECT u.*, o.order_no " + "FROM user u " + "LEFT JOIN order o ON u.id = o.user_id " + "${ew.customSqlSegment}") // 动态插入条件 IPage<UserOrderDTO> selectUserOrders(Page<?> page, @Param(Constants.WRAPPER) LambdaQueryWrapper<User> wrapper); ``` #### 步骤 2:构建跨表条件(Service 层) ```java public IPage<UserOrderDTO> searchOrders(String productName) { LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); // 使用表别名引用其他表字段 wrapper.apply("o.product_name = {0}", productName) // ✅ 正确:order表字段 .eq(User::getStatus, 1); // ✅ 正确:user表字段 return userMapper.selectUserOrders(new Page<>(1, 10), wrapper); } ``` #### 关键点说明: 1. **表别名机制**: - 在 SQL 中通过 `o.product_name` 明确指定 `order` 表字段 - 避免直接写 `product_name`(可能引起歧义) 2. **动态条件注入**: - `${ew.customSqlSegment}` 自动插入 `LambdaQueryWrapper` 生成的条件 - 安全提示:确保 `apply()` 参数使用预编译占位符 `{0}` 防止 SQL 注入 3. **混合条件支持**: ```java // 同时使用本表(Lambda) + 他表(别名)条件 wrapper.apply("o.price > {0}", 100) .ge(User::getAge, 18); ``` --- ### 其他表字段的查询方式对比 | 场景 | 正确方式 | 错误方式 | |-------------------------------|----------------------------------|------------------------| | 引用当前表字段 | `eq(User::getName, "Tom")` | 无 | | 引用关联表字段(WHERE 条件) | `apply("o.product_name={0}",x)` | `eq(Order::getName,x)`[^1] | | 引用关联表字段(SELECT 字段)| SQL 中写 `o.column AS alias` | 实体类直接添加字段[^2]| > **原理说明**: > `LambdaQueryWrapper` 基于当前实体类(如 `User`)的字段生成 SQL,无法直接识别其他实体(如 `Order`)的字段[^4]。必须通过 **显式表别名** 指定关联表字段。 --- ### 复杂场景:多表动态条件 ```java wrapper // 关联表条件 .apply("o.create_time BETWEEN {0} AND {1}", startTime, endTime) // 本表条件 .in(User::getDeptId, deptIds) // 嵌套条件 .and(w -> w.apply("o.status={0}", 1).or().gt(User::getScore, 90)); ``` --- ### 最佳实践建议 1. **始终使用表别名**:多表查询时为每个字段显式指定 `table_alias.column` 2. **DTO 接收结果**:避免污染实体类,用 DTO 接收跨表查询结果 3. **参数化传递**:`apply()` 中使用 `{0}`/`{1}` 占位符确保安全 4. **XML 管理复杂 SQL**:超过 3 表关联时建议使用 XML 映射文件 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值