# 对象条件构造

# 功能介绍

addObjConditions 是一个用于根据对象属性值自动构建查询条件的功能。它可以将一个对象的非空属性自动转换为对应的查询条件,极大简化了查询条件的编写。

# 注解参数说明

所有条件注解都支持以下三个参数:

  1. tableAlias - 表别名

    • 默认为空,表示主表字段
    • 用于指定关联表的别名,实现多表查询条件构建
  2. mappingColumn - 映射列名

    • 默认为空,使用属性名的下划线形式作为列名
    • 当属性名与数据库列名不一致时使用
  3. group - 条件分组

    • 默认为空数组,表示该条件始终生效
    • 类似于Valid分组功能,可以根据不同场景启用不同的查询条件

# 使用示例

# 基础用法

@Data
public class UserQuery {
    @Eq  // 等价于 name = ?
    private String name;
    
    @Like // 等价于 address LIKE ?
    private String address;
    
    @Gt   // 等价于 age > ?
    private Integer age;
}

// 使用
UserQuery query = new UserQuery();
query.setName("张三");
query.setAddress("北京");
query.setAge(18);

wrapper.addObjConditions(query);

// 生成的SQL:
// SELECT * FROM user 
// WHERE name = '张三' 
// AND address LIKE '%北京%' 
// AND age > 18

# 指定表别名

@Data
public class OrderQuery {
    // 主表字段
    @Eq
    private String orderNo;
    
    // 关联用户表字段
    @Eq(tableAlias = "u")  
    private String userName;
    
    // 关联商品表字段
    @Ge(tableAlias = "p")
    private BigDecimal price;

    @OrderBy
    private String orderBy;
}

// 使用
OrderQuery query = new OrderQuery();
query.setOrderNo("OR2024001");
query.setUserName("张三");
query.setOrderBy("orderNo,asc");
query.setPrice(new BigDecimal("100"));

Joins.of(Order.class)
        .leftJoin(Users.class,Order::getUserId,Users::getId,'u')
        .leftJoin(Product.class,Order::getProductId,Product::getId,'p')
        .addObjConditions(query);

// 生成的SQL:
// SELECT * FROM order t 
// LEFT JOIN users u ON u.id = t.user_id
// LEFT JOIN product p ON p.id = t.product_id
// WHERE t.order_no = 'OR2024001'
// AND u.user_name = '张三'
// AND p.price >= 100
// Order By order_no asc

# 自定义列名映射

@Data 
public class ProductQuery {
    // 属性名与列名不一致
    @Eq(mappingColumn = "product_name")
    private String name;
    
    // 关联表+自定义列名
    @Like(tableAlias = "c", mappingColumn = "category_name") 
    private String categoryName;
}

// 使用
ProductQuery query = new ProductQuery();
query.setName("iPhone");
query.setCategoryName("手机");

Joins.of(Product.class)
        .leftJoin(Category.class, Product::getCategoryId, Category::getId,'c')
        .addObjConditions(query);

// 生成的SQL:
// SELECT * FROM product t
// LEFT JOIN category c ON c.id = t.category_id
// WHERE t.product_name = 'iPhone'
// AND c.category_name LIKE '%手机%'

# 条件分组

@Data
public class OrderQuery {
    @Eq
    private String orderNo;
    
    // 列表查询条件 - 创建时间范围
    @Ge(mappingColumn = "create_time", group = QueryGroup.List.class)
    private LocalDateTime startTime;
    @Le(mappingColumn = "create_time", group = QueryGroup.List.class)
    private LocalDateTime endTime;
    
    @In(group = QueryGroup.Export.class)
    private List<Integer> statusList;
}

// 列表查询
OrderQuery query = new OrderQuery();
query.setOrderNo("OR2024001");
query.setStartTime(LocalDateTime.now().minusDays(7));
query.setEndTime(LocalDateTime.now());
wrapper.addObjConditions(query, QueryGroup.List.class);

// 生成的SQL:
// SELECT * FROM order
// WHERE order_no = 'OR2024001'
// AND create_time >= '2024-01-15 00:00:00'
// AND create_time <= '2024-01-22 00:00:00'

// 导出查询
query.setStatusList(Arrays.asList(1, 2, 3));
wrapper.addObjConditions(query, QueryGroup.Export.class);

// 生成的SQL:
// SELECT * FROM order
// WHERE order_no = 'OR2024001'
// AND status IN (1, 2, 3)

# 支持的条件注解

目前支持以下条件注解:

  • @Eq - 等于(=)
  • @Ne - 不等于(<>)
  • @Gt - 大于(>)
  • @Ge - 大于等于(>=)
  • @Lt - 小于(<)
  • @Le - 小于等于(<=)
  • @Like - 模糊查询(LIKE '%值%')
  • @NotLike - 不包含(NOT LIKE '%值%')
  • @LikeLeft - 左模糊(LIKE '%值')
  • @LikeRight - 右模糊(LIKE '值%')
  • @NotLikeLeft - 不以什么开头(NOT LIKE '%值')
  • @NotLikeRight - 不以什么结尾(NOT LIKE '值%')
  • @In - 包含(IN)
  • @NotIn - 不包含(NOT IN)
  • @Between - Between

# 支持的排序注解

  • @OrderBy - OrderBy排序

# 最佳实践

  1. 查询对象命名规范
// 推荐使用 实体名 + Query 作为查询对象名称
public class UserQuery { }
public class OrderQuery { }
  1. 合理使用条件注解
@Data 
public class UserQuery {
    // 精确匹配的字段使用 @Eq
    @Eq
    private String status;
    
    // 模糊搜索的字段使用 @Like
    @Like  
    private String keyword;
    
    // 范围查询的开始和结束时间都映射到 create_time 字段
    @Ge(mappingColumn = "create_time")
    private LocalDateTime startTime;
    @Le(mappingColumn = "create_time")
    private LocalDateTime endTime;
    
    // 多表关联查询
    @Eq(tableAlias = "d")
    private String deptName;
}
  1. 空值处理
// 所有条件注解都会自动过滤空值,无需手动判断
UserQuery query = new UserQuery();
query.setName(null);
query.setAge(18);

wrapper.addObjConditions(query);
// 只会添加 age 的查询条件
  1. 分组使用
@Data
public class OrderQuery {
    // 通用条件
    @Eq
    private String orderNo;
    
    // 列表查询条件 - 创建时间范围
    @Ge(mappingColumn = "create_time", group = QueryGroup.List.class)
    private LocalDateTime startTime;
    @Le(mappingColumn = "create_time", group = QueryGroup.List.class)
    private LocalDateTime endTime;
    
    // 导出条件
    @In(group = QueryGroup.Export.class)
    private List<Integer> statusList;
}

# 注意事项

  1. 表别名使用
  • 主表字段不需要指定tableAlias
  • 关联表字段必须指定tableAlias,且要与join时的别名一致
  • tableAlias区分大小写
  1. 映射列名使用
  • 只有属性名与列名不一致时才需要指定
  • mappingColumn必须是实际的数据库列名
  • 建议统一命名规范,减少映射
  1. 分组使用
  • 建议将分组接口定义在查询对象内部
  • 分组接口使用见名知意的命名
  • 通用条件不指定group
  1. 其他注意
  • 查询对象中的属性类型要与实体类对应
  • 建议将查询对象与实体类分开维护
  • 不要在同一字段上使用多个条件注解

通过合理使用这些注解参数,我们可以:

  1. 实现灵活的多表查询条件构建
  2. 优雅处理字段映射关系
  3. 根据不同场景启用不同的查询条件
  4. 提高代码的可维护性和复用性