likes
comments
collection
share

Bean Searcher v3.8.0 一大波新特性来袭

作者站长头像
站长
· 阅读数 36

上篇:最近火起的 Bean Searcher 与 MyBatis Plus 倒底有啥区别?

介绍

Bean Searcher 是一款专注高级查询的只读 ORM,天生支持联表,免 DTO/VO 转换,使一行代码实现复杂列表检索成为可能!

它可以像 基础组件 ORM 那样使用,同时也拥有 接近低代码 的开发效率。

使用场景

Bean Searcher 专治复杂的检索需求,例如:

  • 普通后端查询

Bean Searcher v3.8.0 一大波新特性来袭

  • 动态检索方式

Bean Searcher v3.8.0 一大波新特性来袭

  • 动态分组查询

Bean Searcher v3.8.0 一大波新特性来袭

以上场景 Bean Searcher 都可以一行代码实现后端代码,极大提高生产力。

设计思想(出发点)

bs.zhxu.cn/guide/lates…

开发效率可以极大提升的原因

bs.zhxu.cn/guide/lates…

框架性能

性能不是主要卖点,但也比传统 ORM 框架平均提升 2 ~ 5 倍(Java 层性能)

详情:gitee.com/troyzhxu/be…

代码仓库

文档与博客

新版本 v3.8.0 的变更

1、提升数据库兼容性

新增 参数转换器 机制,使 Oracle、PgSql 等数据库也同 MySQL 般顺滑。

参考:gitee.com/troyzhxu/be…

2、参数构建器支持 自定义 SQL 条件

自定义 SQL 条件,只能在后端通过参数构建器使用,例如

 Map<String, Object> params = MapUtils.builder()
       // 生成 SQL 条件:u.id in (select user_id from xxx)
       .field(User::getId).sql("$1 in (select user_id from xxx)")
       .build();
List<User> users = searcher.searchList(User.class, params);

用 $n 来表示所需引用的第 n 个字段,再如:

 Map<String, Object> params = MapUtils.builder()
       // 生成 SQL 条件:id < 100 or age > 10
       .field(User::getId, User::getAge).sql("$1 < 100 or $2 > 10")
       .build();
List<User> users = searcher.searchList(User.class, params);

也可以在自定义的 SQL 片段中使用参数占位符 ?(作为 JDBC 参数),例如:

Map<String, Object> params = MapUtils.builder()
       // 生成 SQL 条件:id < ? or age > ?,两个占位符参数分别为:100,10
       .field(User::getId, User::getAge).sql("$1 < ? or $2 > ?", 100, 10)
       .build();
List<User> users = searcher.searchList(User.class, params);

3、分组动态查询条件生成机制

  • 分组字段 生成 where 条件,其它字段 生成 having 条件

例如一个指定了 groupBy 的 SearchBean:

@SearchBean(
    tables = "student_course", 
    groupBy = "course_id"            // 按课程 ID 分组
) 
public class CourseScore {

    @DbField("course_id")
    private long courseId;

    @DbField("sum(score)")           // 该课程的总分(聚合函数:sum)
    private long totalScore;

}

当以 courseId 为条件时:

Map<String, Object> params = MapUtils.builder()
       .field(CourseScore::getCourseId, 101).op(LessThan.class)
       .build();
List<CourseScore> list = searcher.searchList(CourseScore.class, params);

执行 SQL(条件在 where 里):

select course_id, sum(score) from student_course where course_id < 101 group by course_id

当以 totalScore 为条件时:

Map<String, Object> params = MapUtils.builder()
       .field(CourseScore::getTotalScore, 500).op(GreateThan.class)
       .build();
List<CourseScore> list = searcher.searchList(CourseScore.class, params);

执行 SQL(条件在 having 里):

select course_id, sum(score) 
from student_course 
group by course_id 
having sum(score) > 500

当然两者还可以组合:

Map<String, Object> params = MapUtils.builder()
       .field(CourseScore::getCourseId, 101).op(LessThan.class)
       .field(CourseScore::getTotalScore, 500).op(GreateThan.class)
       .build();
List<CourseScore> list = searcher.searchList(CourseScore.class, params);

执行 SQL:

select course_id, sum(score) 
from student_course 
where course_id < 101 
group by course_id 
having sum(score) > 500

4、新增 NotLike 运算符

目前内置的运算符已经有 19 个:

运算符缩写SQL 片段是否忽略空值含义
Equaleqx = ?等于(是缺省默认的运算符)
NotEqualnex != ?不等于
GreaterThangtx > ?大于
GreaterEqualgex >= ?大于等于
LessThanltx < ?小于
LessEquallex <= ?小于等于
Betweenbtx between ?1 and ?2 / x >= ?1 / x <= ?2在...之间(范围查询)
NotBetweennbx not between ?1 and ?2 / x < ?1 / x > ?2不在...之间(范围查询)(since v3.3
Containctx like '%?%'包含(模糊查询)(since v3.2
StartWithswx like '?%'以...开头(模糊查询)
EndWithewx like '%?'以...结尾(模糊查询)
OrLikeolx like ?1 or x like ?2 or ...模糊或匹配(可有多个参数值)(since v3.7
NotLikenkx not like ?反模糊匹配(since v3.8
InListil / mvx in (?, ?, ...)多值查询(InList / il 自 v3.3 新增,之前是 MultiValue / mv
NotInnix not in (?, ?, ...)多值查询(since v3.3
IsNullnlx is null为空(since v3.3
NotNullnnx is not null不为空(since v3.3
Emptyeyx is null or x = ''为空(仅适用于 字符串 类型的字段)
NotEmptynyx is not null and x != ''不为空(仅适用于 字符串 类型的字段)

如果不够,你还可以自定义哦,参阅:bs.zhxu.cn/guide/lates…

5、新增根参数安全机制

先回顾一下逻辑分组:juejin.cn/post/709241…

当指定了组表达式后,所有不在表达式指定组内的 字段参数 都会被 检索器 忽略,例如:

# A 组
A.name = Jack
# 组外字段参数,当 gexpr 非空且合法时将会被忽略
age = 20
# 组表达式
gexpr = A

但有时候组表达式 gexpr 是需要前端指定的,同时后端也需要注入一些参数,并且 不能被忽略,这时该怎么办呢?此时只需多注入一个根组(用 $ 表示)参数即可:

# 组外字段参数,当 gexpr 为空或非法时有效
age = 20
# 根组参数,当 gexpr 非空且合法时有效
$.age = 20

$ 是框架内置的一个组,它与 gexpr 之间永远是 的关系。

为了让某个字段参数不能被忽略,我们必须向检索参数中注入两个参数(如上面的 age$.age),这略显麻烦。为此,v3.8.0 同时增强了参数构建器,使其 field(..) 方法在 未显示指定组 之前,都默认会添加对应的根组参数。例如:

Map<String, Object> params = MapUtils.builder()
        // 未显示指定组 之前调用 field 方法
        .field(User::getAge, 20) 
        // 等效于下面的两行代码:
        //   .put("age", 20) 
        //   .put("$.age", 20) 
        .group("A")
        // 显示指定组 之后调用 field 方法
        .field(User::getName, "Jack") 
        // 只等效于:
        //   .put("A.name", "Jack")
        .build()

所以当后端需要手动添加检索条件时,我们推荐您使用参数构建器。

参阅:bs.zhxu.cn/guide/lates…

6、优化注解省略机制

原本若要在实体类字段上省略 @DbFeild 时,必须满足以下三条件之一:

  • 实体类省略了 @SearchBean 注解
  • 实体类的 @SearchBean 没有指定 tables 属性
  • 实体类的 @SearchBean 指定了 autoMapTo 属性

v3.8.0 之前,tablesautoMapTo 必须 同时出现同时消失 才可以省略 @DbFeild 注解,例如改成这样即可:

@SearchBean(tables="user", autoMapTo="user")
public class UserVO {
    private Long id;    // 省略注解 @DbFeild
    private Long name;  // 省略注解 @DbFeild
}

但是总有小伙伴,不想不想省略 tables,又不想指向 autoMapTo,写成这样:

@SearchBean(tables="user")
public class UserVO {
    private Long id;    // 省略注解 @DbFeild
    private Long name;  // 省略注解 @DbFeild
}

结果让不少人都收到了异常,参考:github.com/ejlchina/be…

为了让大家少踩坑,v3.8.0 让这也兼容了这种的写法。现在要省略 @DbFeild,只需满足以下四个条件之一即可:

  • 实体类省略了 @SearchBean 注解
  • 实体类的 @SearchBean 没有指定 tables 属性
  • 实体类的 @SearchBean.tables 只含一张表(since v3.8.0)
  • 实体类的 @SearchBean 指定了 autoMapTo 属性

参阅:bs.zhxu.cn/guide/lates…

7、其它变更

其它变更就不一一列列举了,大家可以在这里查看:

未来特性

如果觉得不错,点个 Star 吧:

请大家继续关注,感谢一路走来支持 Bean Searcher 的你们,我们会努力做到更好。

上篇:最近火起的 Bean Searcher 与 MyBatis Plus 倒底有啥区别?

转载自:https://juejin.cn/post/7116736773065343012
评论
请登录