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(目 ...
随机推荐
- Docker(开课吧笔记)
1.Docker基本概念 Docker运行在Linux,需要git技能 docker官网解析 来源于容器又不仅仅是容器,第一个版本基于LXC,远远超过容器概念 交付时拿到的是镜像,直接run运 ...
- 苹果ATS特性服务器证书配置指南
配置指南: 需要配置符合PFS规范的加密套餐,目前推荐配置: ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!AD ...
- jquery拖拽插件 tableDnD
http://www.jb51.net/article/39481.htm http://www.poluoluo.com/jzxy/201307/232615.html
- Vim快速入门
学习自:实验楼 Vim具有6种基本模式和5种派生模式 普通模式: vim启动后的默认模式,常用的编辑器命令诸如移动光标,删除文本. 普通模式中,有很多方法进入插入模式,常用 a 或 i 键. 插入模式 ...
- MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ...
下面是我update数据库时打印出来的异常: ### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSynt ...
- 解决Appium 抓取toast
首先我们先看看这个gif,图中需要,要抓取的字符串--->请输入转让份数 1.要导入java-client-5.0.0-SNAPSHOT.jar 包的地址:链接:http://pan.baidu ...
- Ceres Solver for android
最近开发中,需要对图片做一些处理与线性技术,这时就用到了Ceres Solver.如何把Ceres Solver集成到Android里呢? 官网给了一个解决方案,简洁明了: Downloa ...
- 【Hexo】Hexo+Github构建个人博客 (五):错误集
一.报错: ERROR Plugin load failed: hexo-deployer-git 解决方案:执行命令 npm install hexo-deployer-git --save 二. ...
- 万能数据库连接类-Oracle、DB2 、Access 、Sql Server
package cc.apps.report; import java.sql.Connection; import java.sql.DriverManager; import java.sql ...
- E/MediaPlayer: Should have subtitle controller already set
原文链接:http://stackoverflow.com/questions/20087804/should-have-subtitle-controller-already-set-mediapl ...