抛弃Mybatis,拥抱新的ORM 框架!【送源码】

背景

转java后的几年时间里面一直在寻找一个类似.net的orm,不需要很特别的功能,仅希望90%的场景都可以通过强类型语法来编写符合直觉的sql,来操作数据库编写业务。

但是一直没有找到,Mybatis-Plus的单表让我在最初的时间段内看到了希望,不过随着使用的深入越发的觉得Mybatis-Plus只是一个残缺的orm,因为大部分场景不支持表达式或者强类型会导致它本身的很多特性都无法使用,比如你配置了软删除,那么如果你遇到了join不好意思软删除你需要自己处理,很多配置会随着手写sql的加入变的那么的不智能,甚至表现得和sql helper没区别。

别说Mybatis-Plus-Join了,这玩意更逆天,如果一个orm想写出符合自己的sql,需要不断地调试尝试来“拼接”出想要的语句,那么他就称不上一个ORM,连sql builder也算不上。Mybatis-Plus-Join就是这样。

所以在4-5年后我终于忍受不了了,决定自研一款orm。参考现有.net生态十分完整的orm代码和几乎完美符合扩展性和语义性的链式表达式,让.net的orm带到java中。

查询

查询第一条数据

Topic topic = easyQuery.queryable(Topic.class).where(o -> o.eq(Topic::getId, "123")).firstOrNull();==> Preparing: SELECT `id`,`stars`,`title`,`create_time` FROM `t_topic` WHERE `id` = ? LIMIT 1
==> Parameters: 123(String)
<== Time Elapsed: 2(ms)
<== Total: 0

查询并断言至多一条数据

Topic topic = easyQuery.queryable(Topic.class).where(o -> o.eq(Topic::getId, "123")).singleOrNull();==> Preparing: SELECT `id`,`stars`,`title`,`create_time` FROM `t_topic` WHERE `id` = ?
==> Parameters: 123(String)
<== Time Elapsed: 2(ms)
<== Total: 0

查询多条数据

List<Topic> topics = easyQuery.queryable(Topic.class).where(o -> o.eq(Topic::getId, "123")).toList();==> Preparing: SELECT `id`,`stars`,`title`,`create_time` FROM `t_topic` WHERE `id` = ?
==> Parameters: 123(String)
<== Time Elapsed: 2(ms)
<== Total: 0

查询自定义列

Topic topic = easyQuery.queryable(Topic.class).where(o -> o.eq(Topic::getId, "1")).select(o->o.column(Topic::getId).column(Topic::getTitle)).firstOrNull();==> Preparing: SELECT `id`,`title` FROM `t_topic` WHERE `id` = ? LIMIT 1
==> Parameters: 1(String)
<== Time Elapsed: 2(ms)
<== Total: 1

分页查询

 EasyPageResult<Topic> topicPageResult = easyQuery.queryable(Topic.class).where(o -> o.isNotNull(Topic::getId)).toPageResult(1, 20);==> Preparing: SELECT  COUNT(1)  FROM t_topic t WHERE t.`id` IS NOT NULL
<== Total: 1
==> Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM t_topic t WHERE t.`id` IS NOT NULL LIMIT 20
<== Total: 20

将表达式转成匿名表嵌套查询

//  SELECT `id`,`title` FROM `t_topic` WHERE `id` = ? 
Queryable<Topic> query = easyQuery.queryable(Topic.class).where(o -> o.eq(Topic::getId, "1")).select(Topic.class, o -> o.column(Topic::getId).column(Topic::getTitle));List<Topic> list = query.leftJoin(Topic.class, (t, t1) -> t.eq(t1, Topic::getId, Topic::getId)).where((t, t1) -> {t1.eq(Topic::getId, "123");t.eq(Topic::getId, "456");}).toList();SELECT t1.`id`,t1.`title` 
FROM (SELECT t.`id`,t.`title` FROM `t_topic` t WHERE t.`id` = ?) t1 
LEFT JOIN `t_topic` t2 ON t1.`id` = t2.`id` WHERE t2.`id` = ? AND t1.`id` = ? ==> Preparing: SELECT t1.`id`,t1.`title` FROM (SELECT t.`id`,t.`title` FROM `t_topic` t WHERE t.`id` = ?) t1 LEFT JOIN `t_topic` t2 ON t1.`id` = t2.`id` WHERE t2.`id` = ? AND t1.`id` = ?
==> Parameters: 1(String),123(String),456(String)
<== Time Elapsed: 5(ms)
<== Total: 0

子查询

//SELECT * FROM `t_blog` t1 WHERE t1.`deleted` = ? AND t1.`id` = ?Queryable<BlogEntity> subQueryable = easyQuery.queryable(BlogEntity.class).where(o -> o.eq(BlogEntity::getId, "1"));List<Topic> x = easyQuery.queryable(Topic.class).where(o -> o.exists(subQueryable.where(q -> q.eq(o, BlogEntity::getId, Topic::getId)))).toList();==> Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM `t_topic` t WHERE EXISTS (SELECT 1 FROM `t_blog` t1 WHERE t1.`deleted` = ? AND t1.`id` = ? AND t1.`id` = t.`id`)
==> Parameters: false(Boolean),1(String)
<== Time Elapsed: 3(ms)
<== Total: 1

多表join查询

Topic topic = easyQuery.queryable(Topic.class).leftJoin(BlogEntity.class, (t, t1) -> t.eq(t1, Topic::getId, BlogEntity::getId)).where(o -> o.eq(Topic::getId, "3")).firstOrNull();==> Preparing: SELECT t.`id`,t.`stars`,t.`title`,t.`create_time` FROM t_topic t LEFT JOIN t_blog t1 ON t1.`deleted` = ? AND t.`id` = t1.`id` WHERE t.`id` = ? LIMIT 1
==> Parameters: false(Boolean),3(String)
<== Total: 1

流式结果大数据迭代返回

try(JdbcStreamResult<BlogEntity> streamResult = easyQuery.queryable(BlogEntity.class).where(o -> o.le(BlogEntity::getStar, 100)).orderByAsc(o -> o.column(BlogEntity::getCreateTime)).toStreamResult()){LocalDateTime begin = LocalDateTime.of(2020, 1, 1, 1, 1, 1);int i = 0;for (BlogEntity blog : streamResult.getStreamIterable()) {String indexStr = String.valueOf(i);Assert.assertEquals(indexStr, blog.getId());Assert.assertEquals(indexStr, blog.getCreateBy());Assert.assertEquals(begin.plusDays(i), blog.getCreateTime());Assert.assertEquals(indexStr, blog.getUpdateBy());Assert.assertEquals(begin.plusDays(i), blog.getUpdateTime());Assert.assertEquals("title" + indexStr, blog.getTitle());
//            Assert.assertEquals("content" + indexStr, blog.getContent());Assert.assertEquals("http://blog.easy-query.com/" + indexStr, blog.getUrl());Assert.assertEquals(i, (int) blog.getStar());Assert.assertEquals(0, new BigDecimal("1.2").compareTo(blog.getScore()));Assert.assertEquals(i % 3 == 0 ? 0 : 1, (int) blog.getStatus());Assert.assertEquals(0, new BigDecimal("1.2").multiply(BigDecimal.valueOf(i)).compareTo(blog.getOrder()));Assert.assertEquals(i % 2 == 0, blog.getIsTop());Assert.assertEquals(i % 2 == 0, blog.getTop());Assert.assertEquals(false, blog.getDeleted());i++;}} catch (SQLException e) {throw new RuntimeException(e);}==> Preparing: SELECT `id`,`create_time`,`update_time`,`create_by`,`update_by`,`deleted`,`title`,`content`,`url`,`star`,`publish_time`,`score`,`status`,`order`,`is_top`,`top` FROM `t_blog` WHERE `deleted` = ? AND `star` <= ? ORDER BY `create_time` ASC
==> Parameters: false(Boolean),100(Integer)
<== Time Elapsed: 6(ms)

自定义VO返回

List<QueryVO> list = easyQuery.queryable(Topic.class)//第一个join采用双参数,参数1表示第一张表Topic 参数2表示第二张表 BlogEntity.leftJoin(BlogEntity.class, (t, t1) -> t.eq(t1, Topic::getId, BlogEntity::getId))//第二个join采用三参数,参数1表示第一张表Topic 参数2表示第二张表 BlogEntity 第三个参数表示第三张表 SysUser.leftJoin(SysUser.class, (t, t1, t2) -> t.eq(t2, Topic::getId, SysUser::getId)).where(o -> o.eq(Topic::getId, "123"))//单个条件where参数为主表Topic//支持单个参数或者全参数,全参数个数为主表+join表个数 链式写法期间可以通过then来切换操作表.where((t, t1, t2) -> t.eq(Topic::getId, "123").then(t1).like(BlogEntity::getTitle, "456").then(t2).eq(BaseEntity::getCreateTime, LocalDateTime.now()))//如果不想用链式的then来切换也可以通过lambda 大括号方式执行顺序就是代码顺序,默认采用and链接.where((t, t1, t2) -> {t.eq(Topic::getId, "123");t1.like(BlogEntity::getTitle, "456");t1.eq(BaseEntity::getCreateTime, LocalDateTime.now());}).select(QueryVO.class, (t, t1, t2) ->//将第一张表的所有属性的列映射到vo的列名上,第一张表也可以通过columnAll将全部字段映射上去// ,如果后续可以通过ignore方法来取消掉之前的映射关系t.column(Topic::getId).then(t1)//将第二张表的title字段映射到VO的field1字段上.columnAs(BlogEntity::getTitle, QueryVO::getField1).then(t2)//将第三张表的id字段映射到VO的field2字段上.columnAs(SysUser::getId, QueryVO::getField2)).toList();

表单条件动态查询

BlogQuery2Request query = new BlogQuery2Request();
query.setContent("标题");
query.setPublishTimeEnd(LocalDateTime.now());
query.setStatusList(Arrays.asList(1,2));List<BlogEntity> queryable = easyQuery.queryable(BlogEntity.class).whereObject(query).toList();==> Preparing: SELECT `id`,`create_time`,`update_time`,`create_by`,`update_by`,`deleted`,`title`,`content`,`url`,`star`,`publish_time`,`score`,`status`,`order`,`is_top`,`top` FROM `t_blog` WHERE `deleted` = ? AND `content` LIKE ? AND `publish_time` <= ? AND `status` IN (?,?)
==> Parameters: false(Boolean),%标题%(String),2023-07-14T22:37:47.880(LocalDateTime),1(Integer),2(Integer)
<== Time Elapsed: 2(ms)
<== Total: 0

基本类型结果返回

List<String> list = easyQuery.queryable(Topic.class).where(o -> o.eq(Topic::getId, "1")).select(String.class, o -> o.column(Topic::getId)).toList();==> Preparing: SELECT t.`id` FROM `t_topic` t WHERE t.`id` = ?
==> Parameters: 1(String)
<== Time Elapsed: 2(ms)
<== Total: 1

分组查询

List<TopicGroupTestDTO> topicGroupTestDTOS = easyQuery.queryable(Topic.class).where(o -> o.eq(Topic::getId, "3")).groupBy(o->o.column(Topic::getId)).select(TopicGroupTestDTO.class, o->o.columnAs(Topic::getId,TopicGroupTestDTO::getId).columnCount(Topic::getId,TopicGroupTestDTO::getIdCount)).toList();==> Preparing: SELECT t.`id` AS `id`,COUNT(t.`id`) AS `idCount` FROM t_topic t WHERE t.`id` = ? GROUP BY t.`id`
==> Parameters: 3(String)
<== Total: 1//groupKeysAs快速选择并且给别名
List<TopicGroupTestDTO> topicGroupTestDTOS = easyQuery.queryable(Topic.class).where(o -> o.eq(Topic::getId, "3")).groupBy(o->o.column(Topic::getId)).select(TopicGroupTestDTO.class, o->o.groupKeysAs(0, TopicGroupTestDTO::getId).columnCount(Topic::getId,TopicGroupTestDTO::getIdCount)).toList();==> Preparing: SELECT t.`id` AS `id`,COUNT(t.`id`) AS `idCount` FROM t_topic t WHERE t.`id` = ? GROUP BY t.`id`
==> Parameters: 3(String)
<== Total: 1

原生sql片段

String sql = easyQuery.queryable(H2BookTest.class).where(o -> o.sqlNativeSegment("regexp_like({0},{1})", it -> it.expression(H2BookTest::getPrice).value("^Ste(v|ph)en$"))).select(o -> o.columnAll()).toSQL();SELECT id,name,edition,price,store_id FROM t_book_test WHERE regexp_like(price,?)

数据库函数列

用户存储的数据是base64结果,但是内存中是普通的字符串或者其他数据,easy-query提供了无感的使用,譬如pgsql的geo等地理相关数据

数据库函数列:

https://xuejm.gitee.io/easy-query-doc/guide/adv/column-sql-func-auto.html

支持like的高性能加密解密

用来实现支持like模式的高性能加密解密,支持emoji和非emoji两种用户可以自行选择

更多功能比如数据追踪差异更新,数据原子更新,分库分表(老行当了肯定要支持),一款本无依赖双语(java/kotlin)都支持的高性能orm

github地址:

https://github.com/dromara/easy-query

gitee地址:

https://gitee.com/xuejm/easy-query

 ——EOF——

福利:

扫码回复【图书】可免费领取图书管理系统源码

图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/858422.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用golang_Consul代码实现Prometheus监控目标的注册以及动态发现与配置

文章目录 前言一、prometheus发现方式二、监控指标注册架构图三、部分代码展示1.核心思想2.代码目录3、程序入口函数剖析4、settings配置文件5、初始化配置文件及consul6、全局变量7、配置config8、公共方法目录common9、工具目录tools10、service层展示11、命令行参数12、Make…

Qt异常处理

初步警告:异常安全功能不完整!一般情况下应该可以工作&#xff0c;但类仍然可能泄漏甚至崩溃。 Qt本身不会抛出异常。而是使用错误码, 但是C可能会抛出异常。此外&#xff0c;有些类有用户可见的错误消息&#xff0c;例如QIODevice::errorString()或QSqlQuery::lastError()。这…

Android笔记-安装Termux开启ssh,安装vim、android-tool、python等

背景 家里面有个老手机&#xff0c;想将此手机做成一个家庭服务器。控制各种家电。目前准备先控制电视机 流程 用电脑usb连接手机&#xff0c;下载好Termux&#xff0c;在安卓手机上安装好。这里就不记录笔记了&#xff0c;各个手机不一样。 安装好进入手机后&#xff1a; …

Java短路逻辑运算符

Java中的运算符还有短路运算符。 其中就有符号 && 和 || 符号 作用 说明 && 短路与 结果和&相同&#xff0c;但是有短路效果 || 短路或 结果和|相同&#xff0c;但是有短路效果 注意事项&#xff1a; &和|&…

SIM卡将成为历史

近期苹果发布了全新款的 iPad Pro 和 iPad Air&#xff0c;这些新品不仅在性能和设计上带来了令人惊叹的进步&#xff0c;还悄然迎来了一项重要改变&#xff1a;eSIM 技术的支持。此次发布的蜂窝版本 iPad Pro 和 iPad Air 都不再配备物理 SIM 卡槽&#xff0c;这标志着苹果在推…

mfc140.dll是什么文件?mfc140.dll文件下载安装办法

一、mfc140.dll文件功能与作用 mfc140.dll作为Microsoft Foundation Classes库的一部分&#xff0c;提供了一系列的基础功能&#xff0c;这些功能对于开发Windows桌面应用程序至关重要。 2.1 应用程序框架 mfc140.dll封装了应用程序的生命周期管理&#xff0c;包括初始化、运…

Gorm 基础:表映射

这篇文章将以创建事件时间记录功能为示例&#xff0c;介绍如何使用 Gorm 完成数据库表的基本映射、简单的创建表数据操作和注意事项。 数据库表设计 设计一个事件时间记录功能通常需要记录事件的开始时间、结束时间和事件类型&#xff0c;以及一些额外的功能&#xff0c;像事…

代码生成技术技术-janino

文章目录 背景简单例子flink 例子 背景 代码生成技术适合在需要动态代码编译的场景中使用。比如大数据计算场景下&#xff0c;经常会要把flink sql 转成实际的执行计划 简单例子 代码是一个string 类型&#xff0c;直接用janino 编译后&#xff0c;就可以得到加载到jvm里的c…

北京地铁用什么数据结构来处理

北京地铁信息查询系统或相关数据分析系统可能会使用多种数据结构来高效地处理和存储信息。以下是几种可能用到的数据结构及其用途&#xff1a; 图&#xff08;Graph&#xff09;&#xff1a;北京地铁线路可以被建模为一个有向加权图&#xff0c;其中每个站点是一个节点&#xf…

赶论文不用愁:如何利用ChatGPT在3小时内完成论文

在这份指南里&#xff0c;我将详细介绍如何运用ChatGPT 4.0的高级功能来辅助学术研究与文章写作。从挖掘研究课题的初步想法开始&#xff0c;到撰写一篇内容深刻、结构完整的学术论文&#xff0c;我将逐步演示如何在研究的各个阶段中充分利用ChatGPT。值得一提的是&#xff0c;…

编程精粹—— Microsoft 编写优质无错 C 程序秘诀 07:编码中的假象

这是一本老书&#xff0c;作者 Steve Maguire 在微软工作期间写了这本书&#xff0c;英文版于 1993 年发布。2013 年推出了 20 周年纪念第二版。我们看到的标题是中译版名字&#xff0c;英文版的名字是《Writing Clean Code ─── Microsoft’s Techniques for Developing》&a…

POSTMAN接口详解

Postman接口详解 Postman 是一个流行的API开发工具&#xff0c;广泛应用于测试、开发和文档编写。它支持发送各种HTTP请求&#xff0c;管理请求参数、标头、认证和脚本&#xff0c;帮助开发者快速调试和验证API接口的正确性。以下是对Postman接口的详细讲解。 Postman基本功能…

二进制炸弹的fp是什么?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

微信小程序组件

微信小程序组件课后小结 引言 随着移动互联网的快速发展&#xff0c;微信小程序已经成为开发者和用户的重要选择之一。小程序以其轻量化、易用性和高效性&#xff0c;为开发者提供了一种全新的开发方式&#xff0c;也为用户带来了更加便捷的服务体验。本文将对微信小程序组件的…

BigDecimal 小数位的处理(RoundingMode)

前言&#xff1a; 在日常项目开发中&#xff0c;接触小数是常有的事情&#xff0c;而产品对于小数的处理&#xff0c;在不同的业务中有不同的定义&#xff0c;比如四舍五入、截取、向上舍位、向下舍位等等场景&#xff0c;面对如此多的场景&#xff0c;你是否会束手无策&#…

【算法】优先级队列-基础与应用

优先级队列&#xff08;Priority Queue&#xff09;是一种特殊的队列类型&#xff0c;它允许在其元素中分配优先级。与传统的先进先出&#xff08;FIFO&#xff09;队列不同&#xff0c;优先级队列中元素的出队顺序取决于它们的优先级。优先级较高的元素会被优先处理&#xff0…

IOS Swift 从入门到精通: 结构体的访问控制、静态属性和惰性

文章目录 初始化器引用当前实例惰性属性静态属性和方法访问控制总结初始化器 初始化器是一种特殊方法,可提供创建结构体的不同方式。所有结构体都默认带有一个初始化器,称为成员初始化器- 它会要求您在创建结构体时为每个属性提供一个值。 User如果我们创建一个具有一个属性…

windows桌面运维---第八天

1、如何判断环路&#xff1a; 1、执行ping命令&#xff1a;网络测试时发现丢包严重&#xff0c;可能是环路引起的 2、监控MAC地址漂移&#xff1a;频繁的MAC漂移是环路的一个迹象。 3、通过display interface brief | include up命令&#xff0c;查看所有UP接口下的流量 2、…

【Qt笔记①】帮助文档、窗口、按钮、信号和槽、lambda表达式

学习第一天&#xff1a;2024-3-9 文章目录 Qt creator 快捷键帮助文档默认生成的main.cpp逐行解释核心类帮助文档的查阅方法-①代码创建按钮第一个第二个对窗口的其他设置 对象树窗口坐标系信号和槽&#xff08;优点&#xff1a;松散耦合&#xff09;帮助文档的查阅方法-②找信…

价格减免(Lc2288)——模拟

句子 是由若干个单词组成的字符串&#xff0c;单词之间用单个空格分隔&#xff0c;其中每个单词可以包含数字、小写字母、和美元符号 $ 。如果单词的形式为美元符号后跟着一个非负实数&#xff0c;那么这个单词就表示一个 价格 。 例如 "$100"、"$23" 和 …