EF 太重,MyBatis 太轻,ORM 框架到底怎么选 ?
以 EF 为代表的基于 Linq 的 ORM 框架总是 很重。
他们的功能早已超出了一个 ORM 的范畴,
ORM 是 Object Relational Mapping ,从名字上看,其初衷是将 数据库中的字段 与 实体中的属性 进行关联映射,
但是 重型 ORM 框架 做了很多 额外 的事情 :
- 数据库连接
- 数据库事务包装
- 实体缓存
- 实体关联管理
- 数据库表同步
- 这些功能很好,
- 强大的功能往往是死板的,
我们无法编写那些灵活的 Sql 去实现某些简便的操作。
以 MyBatis.NET、Dapper 为代表的,
则是基于开发者自行编写 Sql 的 ORM 框架又 太轻。
因为是自行编写 Sql ,
所以他们非常灵活,
但是用起来很 痛苦。
哪怕是一个简单的 Insert ,Update 也得写 Sql,
而且还无法摆脱 数据库 兼容的问题。
你所编写的那些 Sql 在大部分情况下,只能用于一种 数据库
今天要向大家介绍一个 轻量级、不用写 Sql、可以兼容多数据库 的 ORM 框架
Reface.NPI
什么是 NPI
NPI 全名 .Net Persistent Interface 。
这是一个利用 interface 实现的轻量级 ORM 框架,
它与市面上大多数的 ORM 框架不同,它不基于 Linq 进行数据库操作,而是基于 Method Name。
例如
IList<User> SelectById(int id);
IList<User> SelecyByNameLike(string name);
void UpdatePasswordById(int id, string password);
bool DeleteById(int id);
NPI 提供了将上述 MethodName 和 实际运算时的入参 生成 Sql执行信息 的方法。
此库不实现以下功能
- 通过 AOP 产生 interface 的 Proxy ( 这个功能会在 Reface.AppStarter.NPI 中基于 Castle.DynamicProxy 实现 )
- 对 Sql执行信息 的执行
- 将查询结果映射到对应的实体中 ( 这个功能会在 Reface.AppStarter.NPI 以基于 Dapper 实现 )
- 对事务的管理 ( 这个功能预计在一个由 Reface.AppStarter 构建的一个业务框架中实现 )
不建议直接将此库用于业务功能的开发,
建议对该库进行一定的二次开发或封装后再投入使用,
开发者可以根据系统当前已经依赖的库进行封装。
计划在未来转为 .NetStandard 版本,以同时提供给 .NetCore 使用。
依赖项
- Reface.StateMachine ( 库中对方法名称解析的过程依赖于此库 )
- Reface ( 提供了一些基础的功能和方法,使用 .NetStandard2.0 编写 )
由于使用了 .NetStrand2.0,因此本库需要 .Net framework 4.6.1 及以上版本才能使用。
使用方法
四个分析器
系统中针对四种数据库不同的操作(增删改查),分别提供了四个不同的语义分析器
- ISelectParser
- IInsertParser
- IUpdateParser
- IDeleteParser
这四种转化器能够将一个字符串分析成为结构化的数据库处理结构,如
ISelectParser parser = new DefaultSelectParser();
string command = "ByIdAndName";
SelectInfo info = parser.Parse(command);
// info.Fields = [];
// info.Conditions[0].Field = "Id";
// info.Conditions[1].Field = "Name";
// info.Orders = [];
四种分析器分别能生成四种不同的语句结构:
| Parser | 结果的类型 |
|---|---|
| ISelectParser | SelectInfo |
| IInsertParser | InsertInfo |
| IUpdateParser | UpdateInfo |
| IDeleteParser | DeleteInfo |
这些 xxxInfo 的结构并不复杂,这里将不对其展开进行更多的介绍。
四个分析器的整合
ICommandParser 对四个分析器做了整合,以便我们不关心对方法的区分而直接得到 ICommandInfo 。
SelectInfo , InsertInfo , UpdateIfo 和 DeleteInfo 都实现了 ICommandInfo 接口。
ICommandParser 通过方法的第一个单词对方法名进行分类,哪些前缀属于查询、哪些前缀属于更新,都是由它的实现的。
库中的 DefaultCommandParser 按照下面的 首单词 进行逻辑区分 :
查询语句
- Get
- Select
- Fetch
- Find
- PagingGet
- PagingSelect
- PagingFetch
- PagingFind
新增语句
- Insert
- New
- Create
更新语句
- Update
- Modify
删除语句
- Delete
- Remove
下面的例子是分析了一个更新语句。
ICommandInfo 中的 Type 字段有助于你判断应当将 ICommandInfo 转化为一个具体的 Info 。
string command = "UpdateNameById";
ICommandParser parser = new DefaultCommandParser();
ICommandInfo info = parser.Parse(command);
if (info.Type == CommandInfos.Update)
UpdateInfo updateInfo = (UpdateInfo)info;
// updateInfo.SetFields[0].Field = "Name";
// updateInfo.Conditions[0].Field = "Id";
通过方名和参数生成执行信息
执行信息包含两个信息
- Sql 语句
- Sql 参数
在库中,生成执行信息是由 ISqlCommandGenerator 完成的。
// ISqlCommandGenerator.cs
using System.Reflection;
namespace Reface.NPI.Generators
{
public interface ISqlCommandGenerator
{
SqlCommandDescription Generate(MethodInfo methodInfo, object[] arguments);
}
}
设计该接口的初衷是希望使用方是以 AOP 的方式拦截某个方法的执行,
并将 MethodInfo 和 拦截到的入参 传递给 ISqlCommandGenerator,
再根据生成的执行信息直接执行,得到结果。
目前库中有一个它的实现类型 : DefaultSqlServerCommandGenerator 。
你会从名字上发现,它是面向 SqlServer 的实现,
很明显,不同的 数据库 往往支持的语句并不相同。
因此,为不同的 数据库 编写不同的 ISqlCommandGenerator 是有必要的。
SqlCommandDescripion 是一个简单的数据结构,它包含 SqlCommand 和 Parameters 两个主要的属性,使用这两个属性可以完成后续的 Sql 执行。
注意事项
- 对于表名的获取,是基于 INpiDao<TEntity> 中的 TEntity 来完成的,
通过反射 TEntity 上的 System.ComponentModel.DataAnnotations.Schema.TableAttibute 特征来获取表名。 - 由于 TableAttribute 在很多常见库中出现,所以要注意不要引用错了。
- Reface.NPI 允许你重写对表名的获取,对字段的获取等逻辑,重写方法会在后面的文章中介绍。
方法名及预期 Sql 参照表
| 方法名称 | 期望的 Sql | 说明 |
|---|---|---|
| SelectById | select * from [table] where id = ? | 以 Id 作为条件查询实体 |
| SelectNameAndAgeById | select name, age from [table] where id = ? | 以 Id 作为条件,只查询 Name 和 Age 字段 |
| SelectByRegistertimeGreaterthan | select * from [table] where Registertime > ? | 查询 RegisterTime 大于参数的实体 |
| SelectByRegistertimeGteq | select * from [table] where Registertime >= ? | 查询 RegisterTime 大于等于参数的实体 |
| SelectByIdAndName | select * from [table] where id = ? and name = ? | 按 Id 且 Name 作为条件查询实体 |
| SelectByIdOrName | select * from [table] where id = ? or name = ? | 以 Id 或 Name 作为条件查询实体 |
| SelectByIdOrNameLike | select * from [table] where id = ? or name like ? | 以 Id 或 Name Like 作为条件查询实体 |
| SelectByIdOrderbyName | select * from [table] where id = ? order by name | 以 Id 查询并以 Name 排序 |
| SelectByIdOrderByNameDesc | select * from [table] where id = ? order by name desc | 以 Id 作为条件并以 Name 倒序排序 |
| DeleteById | delete from [table] where id = ? | 以 Id 作为条件删除 |
| UpdatePasswordById | update [table] set password = ? where id = ? | 以 Id 作为条件更新 Password |
| UpdatePasswordByNameLike | update [table] set password = ? where name like ? | 以 Name Like 作为条件更新 Password |
| UpdateStateAndTokenByLastoprtimeGt | update [table] set state=?,token=? where lastoprtime > ? | 以 LastOprTime 大于 作为条件更新 state 和 token |
| UpdateById | update [table] set ... where id = ? | 以 Id 作为条件,并以 Id 以外的字段作为 Set 子句 |
| UpdateWithoutCreatetimeById | update [table] set ... where id = ? | 以 Id 作为条件,并以 Id 和 Createtime 以外的字段作为 Set 子句 |
| UpdateWithoutStateCreatetimeById | update [table] set ... where id = ? | 以 Id 作为条件,并以 Id 、State 和 Createtime 以外的字段作为 Set 子句 |
| InsertWithoutIdCreatetime(Entity) | insert into [table] (...) values(?,...,?) | 排除 Id 和 Createtime 字段新增实现 |
相关链接
下期预告 : 《NPI 方法规则详解》
将详细地说明四种操作所支持的各种操作。
EF 太重,MyBatis 太轻,ORM 框架到底怎么选 ?的更多相关文章
- Abp太重了?轻量化Abp框架
本文首发于个人博客(https://blog.zhangchi.fun/) 在进行框架的选型时,经常会听到"***框架太重了"之类的声音,比如"Abp太重了,不适合我们. ...
- EF、Dapper、NHibernate等ORM框架的比较及优缺点
什么是ORM? ORM的全称是Object Relational Mapping,即对象关系映射.它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样开发人员就可以把对数据库的操 ...
- mybatis(一)常见ORM框架及JDBC操作工具类
转载:https://www.cnblogs.com/wuzhenzhao/p/11075569.html 在Java 程序里面去连接数据库,最原始的办法是使用JDBC 的API.我们先来回顾一下 ...
- 【EF 4】ORM框架及其流行产品之一EF介绍
导读:跳进了多租户切换数据库的坑,那么就继续走下去吧.在我们的项目中,是运用EF实现对数据库的操作,那么EF其实是.NET系统中,基于ORM框架的一个产品实现.在java那边,则有Hibernate和 ...
- ORM框架之EntityFramework介绍
ORM框架之EntityFramework介绍 1. 简介 大家好!我是高堂. 作为一位伪前端程序猿,我给大家介绍一下微软的自家的 ORM框架. ADO.NET Entity Framework 以下 ...
- 轻量级ORM框架初探-Dapper与PetaPoco的基本使用
一.EntityFramework EF是传统的ORM框架,也是一个比较重量级的ORM框架.这里仍然使用EF的原因在于为了突出轻量级ORM框架的性能,所谓有对比才有更优的选择. 1.1 准备一张数据库 ...
- orm框架与缓存的关系
1.mybatis规定,一级缓存没必要bean类实现序列化,但二级缓存bean类必须实现序列化. 因为二级缓存是基于namespace的也就是基于接口的,二级缓存可以设置存储源,可以是redis或者m ...
- ORM框架EF
应用程序和数据库采用Tcp协议通讯 ORM框架有: NHibernate ,Dapper ,Mybatis 底层是 ADO.Net 好处: 1.面向对象 2.没有sql减少学习成本,快速开发 3.编译 ...
- 轻量型ORM框架Dapper的使用
在真实的项目开发中,可能有些人比较喜欢写SQL语句,但是对于EF这种ORM框架比较排斥,那么轻量型的Dapper就是一个不错的选择,即让你写sql语句了,有进行了关系对象映射.其实对于EF吧,我说下我 ...
随机推荐
- python-面向对象小结
面向对象 小结 1:面向对象:就是一种编程思想 简称oop,指挥某某完成能完成的功能 2:面向对象与面向过程的优缺点 : 面向过程: 优点: 复杂问题简答化(一步一步解决), 流程化, 缺点:机械化 ...
- elasticsearch 单机安装
一.elasticsearch下载 1.elastic 官网:https://www.elastic.co/cn/ 2.elasticsearch 下载地址:https://www.elastic.c ...
- SPI总线传输的4种模式
概述 在芯片的资料上,有两个非常特殊的寄存器配置位,分别是 CPOL (Clock POlarity)和 CPHA (Clock PHAse). CPOL配置SPI总线的极性 CPHA配置SPI总线的 ...
- Echarts 自定义legend图片,修改点击之后的颜色图解
第一个问题:echarts 可以自定义图例的图标,百度上很多回答都是引用的相对路径,但是不知道为啥,我的vue项目就是引用不显示,在network里面找不到相应图片 后来我想了个法子,就是先获取到这个 ...
- java算法--稀疏数组
数据结构必要知识 线性结构 线性结构是最常用的数据结构,数据元素之间存在一对一的线性关系. 线性结构有两种不同的存储结构,即顺序存储结构和链式存储结构.顺序存储的线性表称为顺序表,顺序表中的存储元素是 ...
- 安装msyql报错——error: Failed dependencies
报错原因: 1.存在两个版本的msyql-community-release. 解决方法: 1.将不要的哪个进行去除,使用命令: rpm -e --nodeps mysql80-community-r ...
- for循环结合range使用方法
range概念:表示一个数据范围 基本的语法格式:range(开始数据,结束数据(不包括结束数据),步长) 记住一个公式:下一个数据=开始数据+步长 步长:表示的是数据前后的间隔 OK,基本的概念和语 ...
- js运算【按位非】~ (index = ~~this.userIndex)(~~ 双破折号 如果是数字返回数字,如果不是数字 返回0)
index = ~~this.userIndex ~~ 双破折号 如果是数字返回数字,如果不是数字 返回0 这个运算符有点意思:按位非[~] 先来几个例子: ~undefined: -1 ~false ...
- Jenkins的制品管理
Jenkins的制品管理 制品是什么? 也叫产出物或工件.制品是软件开发过程中产生的多种有形副产品之一.广义的制品包括用例.UML图.设计文档等.而狭义的制品就可以简单地理解为二进制包.虽然有些代码是 ...
- [组件封装]微信小程序-日历
描述 切换月份, 当天文案为今天, 日期背景变色, 日期红点标识, 点击选中日期. 效果 源码 calendar.wxml <view class="component"&g ...