OSS.Core基于Dapper封装(表达式解析+Emit)仓储层的构思及实现
最近趁着不忙,在构思一个搭建一个开源的完整项目,至于原因以及整个项目框架后边文章我再说明。既然要起一个完整的项目,那么数据仓储访问就必不可少,这篇文章我主要介绍这个新项目(OSS.Core)中我对仓储层的简单思考和实现过程(当前项目还处在搭建阶段),主要集中在以下几个方面:
1. 数据仓储层的需求
2. ORM框架选择
3. OSS.Core仓储层设计实现
4. 调用示例
下边的实现部分中可能需要你对.NET的 泛型,委托,扩展,表达式等有一个基础了解。正是因为这些语言特性,方便我们对操作共性的抽取统一。
一. 数据仓储层需求
既然是一个完整的项目,数据访问是其最基本的部分,同时,数据访问也是整个项目最容易出现瓶颈的地方。在我的划分中,其承担的角色是负责整个数据的输入输出,不仅仅是针对单数据库(有时甚至多库),有时还需要完成一级缓存的实现,给逻辑层提供最基础的数据支撑。
业务永远是在变化的,那么项目也要具备快速演进的能力,所以我希望数据层能够保持相对的简单,在结构上尽量减少复杂的耦合查询,在性能上尽量减少不必要的消耗,例如反射的大量使用。同时针对每个业务对象完成数据库层面基本的CRUD统一封装实现。如果有需要的时候还能在最少的改动下加入缓存的更新。(对于如何实现不同模块不同缓存存储策略,像Redis,Memcached会在后边文章介绍)
同时,对于一个稍微有点规模的项目来说,解决数据库访问的最快速做法就是实现读写分离,所以,我希望这个框架能够在一开始在底层就实现了读写分离的支持,以避免后期再重头对业务代码的大量修改。
二. ORM 框架选择
当然,如果为了简单和性能,直接ADO.NET连接理论上来说是比较高效的做法,不过这样会造成大量的重复操作逻辑代码,同时也会造成代码的散乱,增加维护复杂度。作为技术人员,不仅需要解决业务问题提高效率,同时也要提高自己的效率,所以我会选择一个ORM框架来完成部分基础工作。
当前在.NET体系下,开源的ORM框架很多,如:Entityframework,NHibernate,iBATIS.NET,Dapper等等,各有特色,基于前面我说的,保证效率的同时,兼顾简单还能最大程度减少性能的损耗,并且提供.net standard标准库下的支持。这里对比之后我选择Dapper这个半自动化的ORM作为仓储层的基础框架,选择原因如下:
1. 其结构简单,整个封装主要集中Dapper.cs文件中,体积很小
2. 封装功能简单强大,对原生SQL的支持上很灵活
这点几乎完胜其他框架,无需任何多余的设置,同时基本上你可调用所有原生ADO.NET的功能,sql语句完全自己掌控,却又无需关心command的参数赋值,以及结果实体转换等。
3. 性能上的高效
很多ORM的实体映射通过反射来完成,这点上Dapper再次展现其魅力,在Commond参数赋值,以及实体转换等关键模块,使用了Reflection.Emit功能,间接实现了MSIL编译层面的赋值实现,之所以说间接,是因为其本身代码还需要编译器生成IL代码。在运行时根据类型属性动态创建赋值委托方法。
三. OSS.Core仓储层设计实现
通过Dapper可以实现在数据库访问部分一层简单的封装,不过我依然需要手动编写不少的sql语句,同时还要进行参数化的处理,包括数据的读写分离等。那么这些功能的实现我将在OSS.Core.RepDapper中完成,为了方便理解,先贴出一个简单的封装后的方法调用传输流程:

在这个图里展示一个简单的方法调用流程,围绕这张图的几个核心部分,我分别介绍下:
1. 接口设计
因为我希望这个是完整的示例项目,所以后边希望能够兼容不同数据库,因此对外的仓储访问都基于接口调用。当然如果你的项目根本没有切换数据库的需求,我更建议去掉这一环节,直接在基类中实现单例模式,业务逻辑层直接调用。
图中可以看到接口层独立于实现部分,我将具体业务实体模型和接口 单独放在了OSS.Core.DomainMos 类库中,一方面是为了实体模型在各模块中的共用,另一方面解耦业务逻辑层(Services)和仓储层(Reps)之间的依赖关系。
同时一个项目中数据库访问代码多数都会以CRUD为主,所以这里我定义了一个基础接口(IBaseRep),其包含的方法主要有(表达式部分在后边介绍):

具体的业务数据接口继承至基础接口就好,其中表达式部分是我自己做了一个封装,后边会简单介绍。
2. 仓储基类实现(BaseRep)
首先,如图所示,我们实现了读写分离的两个扩展,其实最终都会经过Excute方法,那么这里展示下方法的具体实现:

可以看到在这个方法提供了一个针对IDbConnection的委托,提供调用层自由使用Dapper方法的同时,统一了数据访问方法入口,便于日志记录,和排查。
其次,在很多项目中会出现用户和订单在不同库中的这类情况,因为涉及到分库的情况,所以需要子类中能有修改连接串能力,那么这里我通过构造函数的形式,提供了两个可空参数:

可以看到,如果子类中定义了自己的连接串,则以子类自定义为主,否则走默认的连接信息。
最后,我们也实现了针对基础接口方法的具体实现,举一示例:

同时,为了保证子类中能够加入缓存处理,所以采用了虚方法(virtual)的形式,保证子类能够重写。
3. 基于Connection的扩展
这个地方主要分为两个部分,a. 表达式的解析,以及参数化的处理 b. 扩展Connection的Insert,Update...等Dapper没有扩展的方法:
a. 熟悉Expression表达式的朋友应该比较了解,表达式本身是一个树形接口,根据不同的类型,可以不断的解析其子表达式,直到不具备继续解析的可能。所以这个就很简单就是递归的不断迭代,根据其不同的NodeType可以组装不同的sql元素,因为代码较长,可以参见github下的SqlExpressionVisitor.cs类,其中参数的赋值部分,没有采用反射,而是使用的反射发射,代码详见SqlParameterEmit.cs
b. 有了表达式的扩展之后,就可以获取对应的sql和参数,通过this扩展Connection方法即可,代码见ConnoctionExtention.cs
四. 调用示例
1. 我们定义一个简单UserInfoMo实体(包含mobile等属性)
2. 定义接口 IUserInfoRep: IBaseRep
3. 定义实现类 UserInfoRep : BaseRep, IUserInfoRep
在不添加其他代码的基础上,我们就可以完成下面的调用:

当前项目还在搭建中,如果有兴趣的同学也欢迎参与进来,代码详见Github下OSS.Core
=============================
如果你还有其他问题,欢迎关注公众号(OSSCoder)

OSS.Core基于Dapper封装(表达式解析+Emit)仓储层的构思及实现的更多相关文章
- .net core 基于Dapper 的分库分表开源框架(core-data)
一.前言 感觉很久没写文章了,最近也比较忙,写的相对比较少,抽空分享基于Dapper 的分库分表开源框架core-data的强大功能,更好的提高开发过程中的效率: 在数据库的数据日积月累的积累下,业务 ...
- 基于Java的简易表达式解析工具(一)
最近需要用到相关表达式解析的工具,然后去网上搜索,找到了一个用C#写的表达式解析工具,仔细看了功能后发现,这正是我需要的,如果我能将它改造成基于Java语言的方式,岂不是更好吗,所以花了一段时间,把网 ...
- ASP.NET Core 实战:基于 Dapper 扩展你的数据访问方法
一.前言 在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类帮我们实现对于数据库的快速访问,后来,ORM(Object Relatio ...
- .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
本篇我将带着大家一起来对Dapper进行下封装并实现基本的增删改查.分页操作的同步异步方法的实现(已实现MSSQL,MySql,PgSQL).同时我们再实现一下仓储层的代码生成器,这样的话,我们只需要 ...
- 基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil
基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil,把日常能用到的各种CRUD都进行了简化封装,让普通程序员只需关注业务即可,因为非常简单,故直接贴源代码,大家若需使用可以直 ...
- 基于Java的简易表达式解析工具(二)
之前简单的介绍了这个基于Java表达式解析工具,现在把代码分享给大家,希望帮助到有需要的人们,这个分享代码中依赖了一些其他的类,这些类大家可以根据自己的情况进行导入,无非就是写字符串处理工具类,日期处 ...
- 基于EFCore3.0+Dapper 封装Repository
Wei.Repository 基于EFCore3.0+Dapper 封装Repository,实现UnitOfWork,提供基本的CURD操作,可直接注入泛型Repository,也可以继承Repos ...
- 【原创】打造基于Dapper的数据访问层
[原创]打造基于Dapper的数据访问层 前言 闲来无事,花几天功夫将之前项目里用到的一个数据访问层整理了出来.实现单个实体的增删改查,可执行存储过程,可输出返回参数,查询结果集可根据实际情况返回 ...
- Dapper.Common基于Dapper的开源LINQ超轻量扩展
Dapper.Common Dapper.Common是基于Dapper的LINQ实现,支持.net core,遵循Linq语法规则.链式调用.配置简单.上手快,支持Mysql,Sqlserver(目 ...
随机推荐
- JavaScript高级程序设计---学习笔记(一)
今天,2017.3.17开始利用课余时间仔细学习<JavaScript高级程序设计>,将需要掌握的知识点记录下来,争取把书里的所有代码敲一遍并掌握. 1.标识符命名最好是第一个字母小写,剩 ...
- win32最简单的htmlayout图形界面demo
1,下载HTMLayoutSDK,放在workspace. SDK下载地址:http://www.terrainformatica.com/htmlayout/HTMLayoutSDK.zip 2,v ...
- 安全超文本传输协议(HTTPS)详解
一.概念与摘要 HTTPS (Secure Hypertext Transfer Protocol)安全超文本传输协议,是一个安全通信通道,它基于HTTP开发用于在客户计算机和服务器之间交换信息.它使 ...
- 【转】一个工具类(可以控制多层嵌套的movieClip)
好多人也应该遇到和我一样的问题,当设计师给了我们一个多层嵌套的movieClip时,我们在写代码时无法将movieClip完全停止掉,主要是基于好多movieClip有深层嵌套,主时间轴不在最上层导致 ...
- 高吞吐koa日志中间件
Midlog中间件 node服务端开发中少不了日志打点,而在koa框架下的日志打点在多进程环境中日志信息往往无法对应上下文,而且在高并发下直接进行写buffer操作(内核调用writev)也会造成内存 ...
- linux cut命令详解
cut是一个选取命令,就是将一段数据经过分析,取出我们想要的.一般来说,选取信息通常是针对"行"来进行分析的,并不是整篇信息分析的. (1)其语法格式为:cut [-bn] [f ...
- AM335X开发板学习系列——环境搭建(vbox虚拟机ubuntu14.04下minicom的安装和配置)
这个系列是我学习AM335X的总结. 1. ubuntu虚拟机的USB设备,选择启用usbserial 2. ubuntu虚拟机的网络,采用桥接模式,以保证开发板和ubuntu虚拟机能互相ping通 ...
- windows下nginx的安装及使用方法入门
nginx功能之一可以启动一个本地服务器,通过配置server_name和root目录等来访问目标文件 一. 下载 http://nginx.org/ 下载后解压 二. 修改配置文件 ngin ...
- java中json和字符串互转及日期转换 练习
一:以下是用到的jar名称: commons-beanutils-1.6.jar commons-collections-3.2.1.jar commons-lang-2.6.jar commons- ...
- 深度学习入门实战(二)-用TensorFlow训练线性回归
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者 :董超 上一篇文章我们介绍了 MxNet 的安装,但 MxNet 有个缺点,那就是文档不太全,用起来可能 ...