ToB企服应用市场:ToB评测及商务社交产业平台

标题: 流畅的orm让我发现我抵触的是mybatis而不是java [打印本页]

作者: 怀念夏天    时间: 2024-2-22 21:53
标题: 流畅的orm让我发现我抵触的是mybatis而不是java
流畅的orm让我发现我抵触的是mybatis而不是java

背景介绍

  开发.net 也快10年了,到第三年的时候我已经渐渐瓶颈了,于是我在网上找各种资料但是大部分c#资料全是皮毛资料,稍微深一点点就再讲表达式expression,感觉完全没有那个深度,但是同时期的java讲解的都是基本原理,和框架思想,所以遇到瓶颈了我就会看java,我也是那个时候渐渐地掌握了两门语言,对我而言我学的是java的思想(计算机的思想)主要是数据结构和算法思想,这在同时期的c#资料是很难找到相同价值的。但是在使用java的3-4年时间里面那种恶心的orm让我也渐渐对其产生厌恶,因为java在那个时期对orm的需求仅仅只是能实现功能和结果集转对象,更多的精力都是在大数据方向上,所以对我们这些crud仔而言orm及其不友好,尤其是用过c#的orm后,但是在工作不久后除了mybatis就是mybatis-plus,这让业务开发的效率大大降低,bug率大大提升(c#的orm转到java的orm而言),强类型和复杂sql不能共存仿佛成为了javaer口中的理所应当。
  经过不断的努力终于在今年4月份正式发布easy-query orm,这款orm参考了大量的c#的orm框架 efcore、freesql、sqlsugar等,也参考了大量的java的orm框架。站在各位大佬的肩膀上让这个orm的开发周期大大降低,虽然java没有c#的expression(非官方的有但是稳定性和安全性等堪忧),但是通过另辟蹊径我也是找到了一条新的出路也算是让java在编写业务的时候可以流畅一把。
框架介绍
  1. `easy-query`一款轻量级、高性能、强类型、易扩展符合C#开发者的JAVA自研ORM,拥有动态条件动态排序,自定义软删除,自定义条件拦截,单表多表,自定义sql,自定义函数,差异更新,分表分库(支持跨库跨表聚合查询),支持高性能加密解密字段模糊搜索等一系列功能
复制代码
github地址 easy-query https://github.com/xuejmnet/easy-query
gitee地址 easy-query https://gitee.com/xuejm/easy-query
api预览

新版本api entity-query拥有非常流畅和语义化的api,并且继承所有之前的api可用,配合插件做到无需apt既可以动态变更代理对象实现无感开发编程
数据库对象
  1. @Data
  2. @Table("t_topic")
  3. @EntityFileProxy
  4. public class Topic implements ProxyEntityAvailable<Topic , TopicProxy> {
  5.     @Column(primaryKey = true)
  6.     private String id;
  7.     private Integer stars;
  8.     private String title;
  9.     private LocalDateTime createTime;
  10.     @Override
  11.     public Class<TopicProxy> proxyTableClass() {
  12.         return TopicProxy.class;
  13.     }
  14. }
复制代码
按id查询
  1. Topic topic = entityQuery.queryable(Topic.class)
  2.                 .whereById("1").firstOrNull();
  3. ==> Preparing: SELECT `id`,`stars`,`title`,`create_time` FROM `t_topic` WHERE `id` = ? LIMIT 1
  4. ==> Parameters: 1(String)
复制代码
自定义条件查询
  1. List<Topic> list = entityQuery.queryable(Topic.class)
  2.         .where(o -> {
  3.             o.id().eq("1");
  4.             o.createTime().le(LocalDateTime.now());
  5.         })
  6.         .toList();
  7. ==> Preparing: SELECT `id`,`stars`,`title`,`create_time` FROM `t_topic` WHERE `id` = ? AND `create_time` <= ?
  8. ==> Parameters: 1(String),2023-12-16T14:17:04.065(LocalDateTime)
复制代码
count查询
  1. long count = entityQuery.queryable(Topic.class)
  2.         .where(o -> {
  3.             o.title().like("11");
  4.             o.createTime().le(LocalDateTime.now());
  5.         }).count();
  6. ==> Preparing: SELECT COUNT(*) FROM `t_topic` WHERE `title` LIKE ? AND `create_time` <= ?
  7. ==> Parameters: %11%(String),2023-12-16T14:17:04.065(LocalDateTime)
复制代码
返回自定义列
  1. List<Topic> list = entityQuery.queryable(Topic.class)
  2.         .where(o->{
  3.             o.title().like("123");
  4.             o.createTime().ge(LocalDateTime.of(2022,2,1,3,4));
  5.         })
  6.         .orderBy(o -> {
  7.             o.id().asc();
  8.             o.createTime().desc();
  9.         })
  10.         .select(o->o.FETCHER.id().title())//仅返回id和title
  11.         .toList();
  12. ==> Preparing: SELECT t.`id`,t.`title` FROM `t_topic` t WHERE t.`title` LIKE ? AND t.`create_time` >= ? ORDER BY t.`id` ASC,t.`create_time` DESC
  13. ==> Parameters: %123%(String),2022-02-01T03:04(LocalDateTime)
  14. List<Topic> list = entityQuery.queryable(Topic.class)
  15.         .where(o->{
  16.             o.title().like("123");
  17.             o.createTime().ge(LocalDateTime.of(2022,2,1,3,4));
  18.         })
  19.         .orderBy(o -> {
  20.             o.id().asc();
  21.             o.createTime().desc();
  22.         })
  23.         .select(o->o.FETCHER.allFieldsExclude(o.id()))//返回所有字段除了id
  24.         .toList();
  25. ==> Preparing: SELECT t.`stars`,t.`title`,t.`create_time` FROM `t_topic` t WHERE t.`title` LIKE ? AND t.`create_time` >= ? ORDER BY t.`id` ASC,t.`create_time` DESC
  26. ==> Parameters: %123%(String),2022-02-01T03:04(LocalDateTime)
复制代码
分组
  1. List<Topic> list = entityQuery.queryable(Topic.class)
  2.         .where(o->{
  3.             o.title().like("123");
  4.             o.createTime().ge(LocalDateTime.of(2022,2,1,3,4));
  5.         })
  6.         .groupBy(o-> o.id())//多个用GroupBy.of(.....)
  7.         .select(Topic.class,(o,tr)->Select.of(
  8.                 o.id(),
  9.                 o.id().count().as(tr.stars())//count(id) as stars
  10.         ))
  11.         .toList();
  12.         
  13. ==> Preparing: SELECT t.`id`,COUNT(t.`id`) AS `stars` FROM `t_topic` t WHERE t.`title` LIKE ? AND t.`create_time` >= ? GROUP BY t.`id`
  14. ==> Parameters: %123%(String),2022-02-01T03:04(LocalDateTime)
复制代码
分页
  1. EasyPageResult<Topic> pageResult = entityQuery.queryable(Topic.class)
  2.         .where(o -> {
  3.             o.title().like("123");
  4.             o.createTime().ge(LocalDateTime.of(2022, 2, 1, 3, 4));
  5.         })
  6.         .orderBy(o -> {
  7.             o.id().asc();
  8.             o.createTime().desc();
  9.         })
  10.         .select(o -> o.FETCHER.id().title())
  11.         .toPageResult(1, 20);
  12. ==> Preparing: SELECT COUNT(*) FROM `t_topic` t WHERE t.`title` LIKE ? AND t.`create_time` >= ?
  13. ==> Parameters: %123%(String),2022-02-01T03:04(LocalDateTime)
  14. <== Time Elapsed: 2(ms)
  15. <== Total: 1
  16. ==> Preparing: SELECT t.`id`,t.`title` FROM `t_topic` t WHERE t.`title` LIKE ? AND t.`create_time` >= ? ORDER BY t.`id` ASC,t.`create_time` DESC LIMIT 20
  17. ==> Parameters: %123%(String),2022-02-01T03:04(LocalDateTime)
  18. <== Time Elapsed: 3(ms)
  19. <== Total: 20
复制代码
可能第一眼觉得select过于复杂
  1. List<Topic> list = entityQuery.queryable(Topic.class)
  2.         .leftJoin(Topic.class, (t, t1) -> {//第一个参数t表示第一个表,第二个参数t1表示第二个表
  3.             t.id().eq(t1.id());
  4.         })
  5.         .where((t, t1) -> {
  6.             t.title().like("11");
  7.             t1.createTime().le(LocalDateTime.of(2021, 1, 1, 1, 1));
  8.         }).select(Topic.class, (t, t1, tr) -> Select.of(//t表示sql的第一个表,t1表示第二个表,tr表示返回的结果匿名表
  9.                     t.FETCHER.id().stars(),//这两者写法是一样的`FETCHER`是为了链式你也可以不用fetcher
  10.                     t1.FETCHER.id().as(tr.title())
  11.             )).toList();
  12. ==> Preparing: SELECT t.`id`,t.`stars`,t1.`id` AS `title` FROM `t_topic` t LEFT JOIN `t_topic` t1 ON t.`id` = t1.`id` WHERE t.`title` LIKE ? AND t1.`create_time` <= ?
  13. ==> Parameters: %11%(String),2021-01-01T01:01(LocalDateTime)
复制代码
排序
  1. List<Topic> list = entityQuery.queryable(Topic.class)
  2.         .leftJoin(Topic.class, (t, t1) -> {
  3.             t.id().eq(t1.id());
  4.         })
  5.         .where((t, t1) -> {
  6.             t.title().like("11");
  7.             t1.createTime().le(LocalDateTime.of(2021, 1, 1, 1, 1));
  8.         }).select(Topic.class, (t, t1, tr) -> Select.of(
  9.                     t.id(),//不使用`FETCHER`直接返回也是可以的
  10.                     t1.stars(),
  11.                     t1.id().as(tr.title())
  12.             )).toList();
复制代码
生成的sql
  1. List<Topic> list = entityQuery.queryable(Topic.class)
  2.         .leftJoin(Topic.class, (t, t1) -> {
  3.             t.id().eq(t1.id());
  4.         })
  5.         .orderBy((t, t1) -> {
  6.             t.id().asc();
  7.             t1.createTime().desc();
  8.         })
  9.         //查询t表的所有除了id和title,并且返回t1的title取别名为id
  10.         .select(Topic.class,(t,t1,tr)->t.allFieldsExclude(t.id(),t.title())._concat(t1.title().as(tr.id())))
  11.         .toList();
  12. ==> Preparing: SELECT t.`stars`,t.`create_time`,t1.`title` AS `id` FROM `t_topic` t LEFT JOIN `t_topic` t1 ON t.`id` = t1.`id` ORDER BY t.`id` ASC,t1.`create_time` DESC
  13. <== Time Elapsed: 6(ms)
  14. <== Total: 101
复制代码
动态条件动态排序

后端管理往往需要复杂的动态条件组合和动态排序,稍不注意就会产生sql注入等问题
本框架给大伙带来的动态解决方案可以说非常完美,支持单表,多表,单字段排序,多字段排序,并且不会出现sql注入等一系列问题
动态查询1
  1.         List<BlogEntity> list = entityQuery.queryable(BlogEntity.class)
  2.                 .where(o -> {
  3.                     //先对createTime进行格式化之后进行左匹配
  4.                     o.createTime().dateTimeFormat("yyyy-MM-dd").likeMatchLeft("2023");
  5.                 })
  6.                 .select(o -> {
  7.                     //构建子表统计
  8.                     SQLSelectAsExpression subQuery = Select.subQueryAs(() -> {
  9.                         return entityQuery.queryable(BlogEntity.class)
  10.                                 .where(x -> {
  11.                                     x.id().eq(o.id());//条件就是主表的id和自己一样
  12.                                 })
  13.                                 .select(x -> x.id().count());
  14.                     }, o.createTime());//别名
  15.                     return Select.of(
  16.                             o.FETCHER.allFieldsExclude(o.title(), o.top()),
  17.                             subQuery
  18.                     );
  19.                 }).toList();
复制代码
动态查询2
  1. -- 第1条sql数据
  2. SELECT
  3.     t.`id`,
  4.     t.`create_time`,
  5.     t.`update_time`,
  6.     t.`create_by`,
  7.     t.`update_by`,
  8.     t.`deleted`,
  9.     t.`content`,
  10.     t.`url`,
  11.     t.`star`,
  12.     t.`publish_time`,
  13.     t.`score`,
  14.     t.`status`,
  15.     t.`order`,
  16.     t.`is_top`,
  17.     (SELECT
  18.         COUNT(t1.`id`)
  19.     FROM
  20.         `t_blog` t1
  21.     WHERE
  22.         t1.`deleted` = false
  23.         AND t1.`id` = t.`id`) AS `create_time`
  24. FROM
  25.     `t_blog` t
  26. WHERE
  27.     t.`deleted` = false
  28.     AND DATE_FORMAT(t.`create_time`,'%Y-%m-%d') LIKE '2023%'
复制代码
动态查询3

最原始的方法
  1. //前段上传的json对象
  2. @Data
  3. public class SysUserQueryRequest {
  4.     private String name;
  5.     private String account;
  6.     private String departName;
  7.     private String phone;
  8.     private LocalDateTime createTimeBegin;
  9.     private LocalDateTime createTimeEnd;
  10. }
  11. //由前端上传json
  12. SysUserQueryRequest sysUserQueryRequest = new SysUserQueryRequest();
  13. sysUserQueryRequest.setName("小明");
  14. sysUserQueryRequest.setCreateTimeBegin(LocalDateTime.now().plusDays(-10));
  15. sysUserQueryRequest.setCreateTimeEnd(LocalDateTime.now());
  16. sysUserQueryRequest.setPhone("180");
  17. //快速实现分页查询 条件过滤默认非null不加入条件如果是字符串还需满足非空
  18. List<SysUser> pageResult = entityQuery.queryable(SysUser.class)
  19.                 .filterConfigure(NotNullOrEmptyValueFilter.DEFAULT)//非null并且字符串非空即加入条件
  20.                 .where(o -> {
  21.                         o.name().like(sysUserQueryRequest.getName());
  22.                         o.account().like(sysUserQueryRequest.getAccount());
  23.                         o.phone().like(sysUserQueryRequest.getPhone());
  24.                         o.departName().like(sysUserQueryRequest.getDepartName());
  25.                         o.createTime().rangeClosed(sysUserQueryRequest.getCreateTimeBegin(), sysUserQueryRequest.getCreateTimeEnd());
  26.                 })
  27.                 .toList();
  28. ==> Preparing: SELECT `id`,`name`,`account`,`depart_name`,`phone`,`create_time` FROM `t_sys_user` WHERE `name` LIKE ? AND `phone` LIKE ? AND `create_time` >= ? AND `create_time` <= ? LIMIT 10
  29. ==> Parameters: %小明%(String),%180%(String),2023-11-11T21:51:34.740(LocalDateTime),2023-11-21T21:51:34.740(LocalDateTime)
复制代码
动态排序
  1. @Data
  2. public class SysUserQueryRequest {
  3.     @EasyWhereCondition
  4.     private String name;
  5.     @EasyWhereCondition
  6.     private String account;
  7.     @EasyWhereCondition
  8.     private String departName;
  9.     @EasyWhereCondition
  10.     private String phone;
  11.     @EasyWhereCondition(type = EasyWhereCondition.Condition.RANGE_LEFT_CLOSED,propName = "createTime" )
  12.     private LocalDateTime createTimeBegin;
  13.     @EasyWhereCondition(type = EasyWhereCondition.Condition.RANGE_RIGHT_CLOSED,propName = "createTime" )
  14.     private LocalDateTime createTimeEnd;
  15. }
  16. //由前端上传json
  17. SysUserQueryRequest sysUserQueryRequest = new SysUserQueryRequest();
  18. sysUserQueryRequest.setName("小明");
  19. sysUserQueryRequest.setCreateTimeBegin(LocalDateTime.now().plusDays(-10));
  20. sysUserQueryRequest.setCreateTimeEnd(LocalDateTime.now());
  21. sysUserQueryRequest.setPhone("180");
  22. //快速实现分页查询 动态对象条件
  23. EasyPageResult<SysUser> pageResult = entityQuery.queryable(SysUser.class)
  24.                         .whereObject(sysUserQueryRequest)
  25.                         .toPageResult(1, 10);
  26. ==> Preparing: SELECT `id`,`name`,`account`,`depart_name`,`phone`,`create_time` FROM `t_sys_user` WHERE `name` LIKE ? AND `phone` LIKE ? AND `create_time` >= ? AND `create_time` <= ? LIMIT 10
  27. ==> Parameters: %小明%(String),%180%(String),2023-11-11T21:51:34.740(LocalDateTime),2023-11-21T21:51:34.740(LocalDateTime)
复制代码
whereObject配合orderByObject将form表单查询的难度降低到了一个人人可用的水平
最后

可能有很多小伙伴会推荐我jpa或者jooq我想说如果我没能力那么我可能会选择他们,如果他们支持国产数据库我可能会选择他们,但是你我更愿意推荐easy-query因为我会聆听开发者的声音起码你叫的动我,我是一个在crud混的菜鸟开发,crud的困难,orm的困难必须是一个混迹在业务开发的程序员才能开发出来的好框架,在没开发出这个api的时候已经有很多小伙伴使用lambda的api进行了开发反向非常不错,期待您的使用。
easy-query

文档地址 https://xuejm.gitee.io/easy-query-doc/
GITHUB地址 https://github.com/xuejmnet/easy-query
GITEE地址 https://gitee.com/xuejm/easy-query

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4