# 对象条件构造
# 功能介绍
addObjConditions 是一个用于根据对象属性值自动构建查询条件的功能。它可以将一个对象的非空属性自动转换为对应的查询条件,极大简化了查询条件的编写。
# 注解参数说明
所有条件注解都支持以下三个参数:
tableAlias- 表别名- 默认为空,表示主表字段
 - 用于指定关联表的别名,实现多表查询条件构建
 
mappingColumn- 映射列名- 默认为空,使用属性名的下划线形式作为列名
 - 当属性名与数据库列名不一致时使用
 
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排序
# 最佳实践
- 查询对象命名规范
 
// 推荐使用 实体名 + Query 作为查询对象名称
public class UserQuery { }
public class OrderQuery { }
- 合理使用条件注解
 
@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;
}
- 空值处理
 
// 所有条件注解都会自动过滤空值,无需手动判断
UserQuery query = new UserQuery();
query.setName(null);
query.setAge(18);
wrapper.addObjConditions(query);
// 只会添加 age 的查询条件
- 分组使用
 
@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;
}
# 注意事项
- 表别名使用
 
- 主表字段不需要指定tableAlias
 - 关联表字段必须指定tableAlias,且要与join时的别名一致
 - tableAlias区分大小写
 
- 映射列名使用
 
- 只有属性名与列名不一致时才需要指定
 - mappingColumn必须是实际的数据库列名
 - 建议统一命名规范,减少映射
 
- 分组使用
 
- 建议将分组接口定义在查询对象内部
 - 分组接口使用见名知意的命名
 - 通用条件不指定group
 
- 其他注意
 
- 查询对象中的属性类型要与实体类对应
 - 建议将查询对象与实体类分开维护
 - 不要在同一字段上使用多个条件注解
 
通过合理使用这些注解参数,我们可以:
- 实现灵活的多表查询条件构建
 - 优雅处理字段映射关系
 - 根据不同场景启用不同的查询条件
 - 提高代码的可维护性和复用性
 
