抛弃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…

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

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

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

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

赶论文不用愁:如何利用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…

二进制炸弹的fp是什么?

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

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

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

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

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

轨迹规划系列之S型速度曲线绝对值定位功能块(Codesys源代码)

1、轨迹规划的作用 轨迹规划的作用(前馈速度+位置插补)-CSDN博客文章浏览阅读13次。轨迹规划可以产生运动控制系统位置闭环控制所需要的前馈速度和插补位置值。前馈速度+PID位置闭环控制典型应用可以参考下面文章链接:1、S7-1200PLC和V90伺服通过工艺对象实现定位控制S7-1200…

表驱动法 -优化逻辑分支

表驱动法 -优化逻辑分支 定义 表驱动法&#xff08;Table-Driven Approach&#xff09;是一种编程模式&#xff0c;可以将输入变量作为直接或间接索引在表里查找所需的结果或处理函数&#xff0c;而不使用逻辑语句&#xff08;if-else 和 switch-case&#xff09;。索引表可以…

VMware与windows的共享文件夹没找到怎么办?

如果这样子添加&#xff0c;在ubuntu中还是没能找到。开机后有的时候仍然未发现共享文件夹。 二、解决办法 使用如下指令&#xff1a; sudo mount -t fuse.vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other /mnt/hgfs/ 是挂载点&#xff0c;也可以指定其它挂载点 -o allow_other…

DHCP原理1-单个局域网出现多个DHCP服务器会发生什么

1. 背景 DHCP全称是Dynamic Host Configuration Protocol。其协议标准是RFC1541&#xff08;已被RFC2131取代&#xff09;&#xff0c;主要实现服务器向客户端动态分配IP地址&#xff08;如IP地址、子网掩码、网关、DNS&#xff09;和配置信息。其系统架构是标准的C/S架构。RFC…

自学SAP是学习ECC版本还是S4版本?

很多人想学SAP&#xff0c;问我应该学ECC版本还是S4版本&#xff0c;我的建议如果你是自学的话&#xff0c;我个人建议使用ECC版本就行&#xff0c;因为这两个版本前台业务和后台配置的操作差异并不大&#xff0c;主要差异在于数据库的差异&#xff0c;前台业务操作和后台系统配…

OS复习笔记ch12-1

文件系统 概述 文件是大多数应用程序的核心要素&#xff0c;文件系统是操作系统对用户来说最重要的部分之一。 本章的主要内容见下图&#xff1a; 文件&#xff0c;大家耳熟能详的就是的docx、pdf、jpg、MP4等各种后缀文件&#xff0c;根据任务需要文件又分成了文本、图片、…

超越YOLOv8,飞桨推出精度最高的实时检测器RT-DETR!

众所周知&#xff0c;实时目标检测( Real-Time Object Detection )一直由 YOLO 系列模型主导。 飞桨在去年 3 月份推出了高精度通用目标检测模型 PP-YOLOE &#xff0c;同年在 PP-YOLOE 的基础上提出了 PP-YOLOE 。后者在训练收敛速度、下游任务泛化能力以及高性能部署能力方面…

我国目前常用的卫星影像星座有哪些(高分二号、高分七号、吉林一号、高景一号······)

​ 点击下方全系列课程学习 点击学习—>ArcGIS全系列实战视频教程——9个单一课程组合系列直播回放 点击学习——>遥感影像综合处理4大遥感软件ArcGISENVIErdaseCognition 中国目前的遥感卫星在数量、种类和应用领域上都取得了显著进展&#xff0c;覆盖了陆地、气象、海…

ViT:5 Knowledge Distillation

实时了解业内动态&#xff0c;论文是最好的桥梁&#xff0c;专栏精选论文重点解读热点论文&#xff0c;围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型重新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;…

Java17 --- SpringSecurity之前后端分离处理

目录 一、实现前后端分离 1.1、导入pom依赖 1.2、认证成功处理 1.3、认证失败处理 1.4、用户注销处理 1.5、请求未认证处理 1.6、跨域处理 1.7、用户认证信息处理 1.8、会话并发处理 一、实现前后端分离 1.1、导入pom依赖 <dependency><groupId>co…

【python】python股票量化交易策略分析可视化(源码+数据集+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

【fastapi+mongodb】使用motor操作mongodb(三)

本篇文章介绍mongodb的删和改&#xff0c;下面是前两篇文章的链接&#xff1a; 【fastapimongodb】使用motor操作mongodb 【fastapimongodb】使用motor操作mongodb&#xff08;二&#xff09; delete delete 的用法基本和查找一致&#xff0c;包括delete_one&#xff08;删除…