以 EF 为代表的基于 Linq 的 ORM 框架总是 很重。
他们的功能早已超出了一个 ORM 的范畴, ORM 是 Object Relational Mapping ,从名字上看,其初衷是将 数据库中的字段 与 实体中的属性 进行关联映射, 但是 重型 ORM 框架 做了很多 额外 的事情 :
我们无法编写那些灵活的 Sql 去实现某些简便的操作。
以 MyBatis.NET、Dapper 为代表的, 则是基于开发者自行编写 Sql 的 ORM 框架又 太轻。
因为是自行编写 Sql , 所以他们非常灵活, 但是用起来很 痛苦。 哪怕是一个简单的 Insert ,Update 也得写 Sql,
而且还无法摆脱 数据库 兼容的问题。 你所编写的那些 Sql 在大部分情况下,只能用于一种 数据库
今天要向大家介绍一个 轻量级、不用写 Sql、可以兼容多数据库 的 ORM 框架
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执行信息 的方法。
此库不实现以下功能
不建议直接将此库用于业务功能的开发, 建议对该库进行一定的二次开发或封装后再投入使用, 开发者可以根据系统当前已经依赖的库进行封装。
计划在未来转为 .NetStandard 版本,以同时提供给 .NetCore 使用。
由于使用了 .NetStrand2.0,因此本库需要 .Net framework 4.6.1 及以上版本才能使用。
系统中针对四种数据库不同的操作(增删改查),分别提供了四个不同的语义分析器
这四种转化器能够将一个字符串分析成为结构化的数据库处理结构,如
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 按照下面的 首单词 进行逻辑区分 :
查询语句
新增语句
更新语句
删除语句
下面的例子是分析了一个更新语句。 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";
执行信息包含两个信息
在库中,生成执行信息是由 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 执行。
方法名称 | 期望的 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 框架到底怎么选 ?
原文:https://www.cnblogs.com/ShimizuShiori/p/12666395.html