本文原始路径: https://www.zybuluo.com/Ivony/note/14074html
DbUtility v3 是一个开源的轻量级数据库访问框架,源代码经过 Apache 协议发布,能够用于商业用途。最新的版本能够经过 NuGet 进行下载,项目及源代码下载地址:git
https://github.com/Ivony/DbUtility程序员
DbUtility 第一个版本公开于七年前,关于 DbUtility 的历史和 DbUtility 的使用,请参考下面这篇博客:github
http://www.cnblogs.com/Ivony/p/3659746.html
https://www.zybuluo.com/Ivony/note/8277数据库
做为一个开源项目,DbUtility 不只仅致力于帮助你们简化数据库访问,也很是欢迎和期待你们的共同参与,不管是提交 Bug 或者单元测试,或是新的特性需求,以及本身动手为 DbUtility 增长更多有趣的功能,都是参与开源项目的方式。这篇文章面向全部有志于为 DbUtility 增添自定义功能的程序员,介绍 DbUtility 的扩展架构。架构
DbUtility v3 相较于以前版本的最大区别,也是 DbUtility v3 傲视其余轻量级数据库访问框架的地方,就是其优良的扩展架构。正如以前的介绍所述,DbUtility 将一个数据库查询分为三个部分:框架
这三个部分各有一个关键的接口,分别为:异步
譬如说 SqlDbUtility 类型即是面向 SQL Server 数据库的查询执行器实现类型,其声明为:ide
public class SqlDbUtility : IAsyncDbExecutor<ParameterizedQuery>, IAsyncDbExecutor<StoredProcedureQuery>, IDbTransactionProvider<SqlDbUtility>
IAsyncDbExecutor
是 IDbExecutor
的异步版本,表示能够异步执行指定类型的查询。能够看出来SqlDbUtility实现了两个查询执行器接口,分别是 IAsyncDbExecutor<ParameterizedQuery>
和 IAsyncDbExecutor<StoredProcedureQuery>
这表示这个类型的对象既能够执行 ParameterizedQuery
类型(参数化查询)的查询,也能执行 StoredProcedureQuery
类型(存储过程)的查询。函数
接下来咱们尝试扩展一个查询构建方法,就像T( "SELECT * FROM Users" )
同样。
假定咱们常常会遇到一个场景,须要获取某个表的全部数据,若是直接使用T来构建参数化查询,则所需写的SQL语句不少: SELECT * FROM TableName
,咱们但愿简化为 DT( "TableName" )
的形式,该如何作呢?
首先咱们要肯定咱们是否须要构建一种新的查询类型,由于构建新的查询类型,须要同时修改查询执行器,在本例中暂不涉及这么深刻的问题。咱们假定暂且借用参数化查询对象,只是简化其生成代码。
那么首先咱们须要了解的一个事实是,全部的查询构建方法其实都是扩展方法,针对特定的查询执行器,对其进行扩展。若是咱们生成的是一个参数化查询,那么咱们须要一个参数化查询执行器才能执行,因此咱们要针对参数化查询执行器进行扩展。首先新建一个扩展方法所需的静态类型:
public static class MyExtensions { }
值得注意的是定义扩展方法的类型必须是静态类型。
而后咱们添加一个扩展方法,由于咱们最终生成的查询类型是参数化查询,因此咱们须要对能够执行参数化查询的对象进行扩展,像这样:
public static void DT( this IDbExecutor<ParameterizedQuery> executor, string tableName ) { throw new NotImplementedException(); }
请注意我这边的返回值类型尚未填写,由于这里涉及到另外一个问题,单纯的查询对象是不能被执行的,为了达到 db.DT( "Users" ).ExecuteDataTable()
这样的效果,咱们须要把查询对象和查询执行器捆绑起来,这个捆绑后的对象的类型为 IDbExecutableQuery
(意为可执行的查询),因此咱们须要把返回值设置为 IDbExecutableQuery
类型:
public static IDbExecutableQuery DT( this IDbExecutor<ParameterizedQuery> executor, string tableName ) { throw new NotImplementedException(); }
DbUtility 已经为咱们提供了现成的 IDbExecutableQuery
的实现,即 DbExecutableQuery<T>
类型,咱们只须要构建一个查询对象,再连同查询执行器一块儿调用这个类型的构造函数便可:
public static IDbExecutableQuery DT( this IDbExecutor<ParameterizedQuery> executor, string tableName ) { ParameterizedQuery query = null; return new DbExecutableQuery<ParameterizedQuery>( executor, query ); }
最后,咱们须要构建一个参数化查询对象,参数化查询对象做为基础查询对象,有不少种方式来构建,最多见的就是利用模板来构建,若是直接调用 db.T
方法,事实上构建出来的是 DbExecutableQuery<ParameterizedQuery>
类型的对象,好在系统提供了一个静态类型 Db
来对这些常见任务提供支持:
public static IDbExecutableQuery DT( this IDbExecutor<ParameterizedQuery> executor, string tableName ) { ParameterizedQuery query = Db.T( "SELECT * FROM " + tableName ); return new DbExecutableQuery<ParameterizedQuery>( executor, query ); }
至此,咱们的第一个扩展就已经完成了,立刻来试一下:
var db = SqlDbUtility.Create( "Database" ); var data = db.DT( "Users" ).ExecuteDataTable();
事实上你知道吗,db.T
这个方法,其内部实现就是这样的
如下摘自DbUtility v3源代码:
public static DbExecutableQuery<ParameterizedQuery> Template( this IDbExecutor<ParameterizedQuery> executor, string template, params object[] parameters ) { return new DbExecutableQuery<ParameterizedQuery>( executor, TemplateParser.ParseTemplate( template, parameters ) ); } public static DbExecutableQuery<ParameterizedQuery> T( this IDbExecutor<ParameterizedQuery> executor, string template, params object[] parameters ) { return Template( executor, template, parameters ); }
接下来,咱们把这个方法再进一步扩展,咱们但愿用户调用这个方法的时候,再也不返回一个可执行的查询对象,而是直接执行查询,并将 DataTable 返回就行了,相信聪明的你应该很快就能想到怎样写了:
public static class MyExtensions { public static DataTable DT( this IDbExecutor<ParameterizedQuery> executor, string tableName ) { ParameterizedQuery query = Db.T( "SELECT * FROM " + tableName ); return new DbExecutableQuery<ParameterizedQuery>( executor, query ).ExecuteDataTable(); } }
没错,借助优秀的可扩展架构,DbUtility能够被任意改造为任何你所喜欢 API 的形式,这种逆天的扩展性,是深深的植入在 DbUtility 总体架构模型设计中的。构成了 DbUtility 无与伦比的体验。