一、前言
在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类帮我们实现对于数据库的快速访问,后来,ORM(Object Relational Mapping,对象关系映射)出现了,我们开始使用 EF、Dapper、NHibernate,亦或是国人的 SqlSugar 代替我们原来的 SqlHelper.cs。通过这些 ORM 工具,我们可以很快速的将数据库中的表与代码中的类进行映射,同时,通过编写 SQL 或是 Lambda 表达式的方式,更加便捷的实现对于数据层的访问。
就像文章标题中所说的这样,在这个项目中我是使用的 Dapper 来进行的数据访问,每个人都有自己的编程习惯,本篇文章只是介绍我在 Grapefruit.VuCore 这个项目中是如何基于 Dapper 创建自己使用的帮助方法的,不会涉及各种 ORM 工具的对比,请友善查看、讨论。
系列目录地址:ASP.NET Core 项目实战
仓储地址:https://github.com/Lanesra712/Grapefruit.VuCore
二、Step by Step
1、整体思路
在 Grapefruit.VuCore 这个项目中,我选择将 SQL 语句存储在 XML 文件中(XML 以嵌入的资源的方式嵌入到程序集中),通过编写中间件的方式,在程序运行时将存储有 SQL 语句的 XML 程序集写入到 Redis 缓存中。当使用到 SQL 语句时,通过 Redis 中的 Key 值进行获取到 Value,从而将 SQL 语句与我们的代码进行拆分。
涉及到的类文件主要是在以下的类库中,基于 Dapper 的数据访问代码则位于基础构造层(02_Infrastructure)中,而使用到这些数据访问代码的,有且仅在位于领域层(03_Domain)中的代码。同时,领域层的文件分布结构和应用层(04_Applicatin)保持相同。
2、扩展数据访问方法
在使用 Dapper 之前,我们首先需要在 Grapefruit.Infrastructure 这个类库中添加对于 Dapper 的引用。同时,因为需要将 SQL 语句存储到 Redis 缓存中,与之前使用 Redis 存储 Token 时相同,这里,也是使用的微软的分布式缓存接口,因此,同样需要添加对于此 DLL 的引用。
Install-Package Dapper
Install-Package Microsoft.Extensions.Caching.Abstractions
在 Grapefruit.Infrastructure 类库中创建一个 Dapper 文件夹,我们基于 Dapper 的扩展代码全部置于此处,整个的代码结构如下图所示。
在整个 Dapper 文件夹下类/接口/枚举文件,主要可以按照功能分为三部分。
2.1、辅助功能文件
主要包含 DataBaseTypeEnum 这个枚举类以及 SqlCommand 这个用来将存储在 XML 中的 SQL 进行映射的帮助类。
DataBaseTypeEnum 这个数据库类型枚举类主要定义了可以使用的数据库类型。我们知道,Dapper 这个 ORM 主要是通过扩展 IDbConnection 接口,从而给我们提供附加的数据操作功能,而我们在创建数据库连接对象时,不管是 SqlConnection 还是 MySqlConnection 最终对于数据库最基础的操作,都是继承于 IDbConnection 这个接口。因此,我们可以在后面创建数据库连接对象时,通过不同的枚举值,创建针对不同数据库操作的数据库连接对象。
public enum DataBaseTypeEnum { SqlServer = 1, MySql = 2, PostgreSql = 3, Oracle = 4 }
SqlCommand 这个类文件只是定义了一些属性,因为我是将 SQL 语句写到 XML 文件中,同时会将 XML 文件存储到 Redis 缓存中,因此,SqlCommand 这个类主要用来将我们获取到的 SQL 语句与类文件做一个映射关系。
public class SqlCommand { /// <summary> /// SQL语句名称 /// </summary> public string Name { get; set; } /// <summary> /// SQL语句或存储过程内容 /// </summary> public string Sql { get; set; } }
2.2、SQL 存储读取
对于 SQL 语句的存储、读取,我定义了一个 IDataRepository 接口,DataRepository 继承于 IDataRepository 实现对于 SQL 语句的操作。
public interface IDataRepository { /// <summary> /// 获取 SQL 语句 /// </summary> /// <param name="commandName"></param> /// <returns></returns> string GetCommandSQL(string commandName); /// <summary> /// 批量写入 SQL 语句 /// </summary> void LoadDataXmlStore(); }
存储 SQL 的 XML 我是以附加的资源存储到 dll 中,因此,这里我是通过加载 dll 的方式获取到所有的 SQL 语句,之后,根据 Name 属性判断 Redis 中是否存在,当不存在时就写入 Redis 缓存中。核心的代码如下所示,如果你需要查看完整的代码,可以去 Github 上查看。
/// <summary> /// 载入dll中包含的SQL语句 /// </summary> /// <param name="fullPath">命令名称</param> private void LoadCommandXml(string fullPath) { SqlCommand command = null; Assembly dll = Assembly.LoadFile(fullPath); string[] xmlFiles = dll.GetManifestResourceNames(); for (int i = 0; i < xmlFiles.Length; i++) { Stream stream = dll.GetManifestResourceStream(xmlFiles[i]); XElement rootNode = XElement.Load(stream); var targetNodes = from n in rootNode.Descendants("Command") select n; foreach (var item in targetNodes) { command = new SqlCommand { Name = item.Attribute("Name").Va