本文原始路径: https://www.zybuluo.com/Ivony/note/14074

前言

DbUtility v3 是一个开源的轻量级数据库访问框架,源代码通过 Apache 协议发布,可以用于商业用途。最新的版本可以通过 NuGet 进行下载,项目及源代码下载地址:

https://github.com/Ivony/DbUtility

DbUtility 第一个版本公开于七年前,关于 DbUtility 的历史和 DbUtility 的使用,请参考下面这篇博客:

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 将一个数据库查询分为三个部分:

  • 查询执行器
  • 查询构建器
  • 结果构建器

这三个部分各有一个关键的接口,分别为:

  • IDbExecutor where T : IDbQuery 定义某种类型查询的查询执行器。
  • IDbQuery 定义特定的数据库查询
  • IDbExecuteContext 定义数据库查询执行上下文,其中包括 DataReader 对象。

譬如说 SqlDbUtility 类型便是面向 SQL Server 数据库的查询执行器实现类型,其声明为:

public class SqlDbUtility :
IAsyncDbExecutor<ParameterizedQuery>,
IAsyncDbExecutor<StoredProcedureQuery>,
IDbTransactionProvider<SqlDbUtility>

IAsyncDbExecutorIDbExecutor 的异步版本,表示可以异步执行指定类型的查询。可以看出来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 无与伦比的体验。

扩展 DbUtility (1)的更多相关文章

  1. DbUtility Ex

    扩展 DbUtility (1) 2014-05-22 21:48 by Ivony..., 234 阅读, 3 评论, 收藏, 编辑 本文原始路径: https://www.zybuluo.com/ ...

  2. DbUtility v3 背后的故事

    DbUtility v3 背后的故事 时间 DbUtility v3构思了差不多大半年,真正开发到第一个版本发布到NuGet却只花了50天.中途大量时间在完善 Jumony 3,只有三周来开发DbUt ...

  3. DbUtility v3

    DbUtility v3 历史 七年前,也就是2007年,我在博客园写了一篇博文,开源并发布了恐怕是我第一个开源项目,DbUtility.其设计的初衷就是为了简化ADO.NET繁琐的数据库访问过程,提 ...

  4. Asp.net Boilerplate之AbpSession扩展

    当前Abp版本1.2,项目类型为MVC5. 以属性的形式扩展AbpSession,并在"记住我"后,下次自动登录也能获取到扩展属性的值,版权归"角落的白板报"所 ...

  5. 恢复SQL Server被误删除的数据(再扩展)

    恢复SQL Server被误删除的数据(再扩展) 大家对本人之前的文章<恢复SQL Server被误删除的数据> 反应非常热烈,但是文章里的存储过程不能实现对备份出来的日志备份里所删数据的 ...

  6. .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法

    .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...

  7. .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类

    .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类 0x00 为什么要引入扩展方法 有的中间件功能比较简单,有的则比较复杂,并且依赖其它组件.除 ...

  8. 采用EntityFramework.Extended 对EF进行扩展(Entity Framework 延伸系列2)

    前言 Entity Framework 延伸系列目录 今天我们来讲讲EntityFramework.Extended 首先科普一下这个EntityFramework.Extended是什么,如下: 这 ...

  9. Dapper扩展之~~~Dapper.Contrib

    平台之大势何人能挡? 带着你的Net飞奔吧!http://www.cnblogs.com/dunitian/p/4822808.html#skill 上一篇文章:Dapper逆天入门~强类型,动态类型 ...

随机推荐

  1. js 自动插入分号

    先来看一个例子: function get(){ return { a:1 } } var r=get(); console.log(r); 似乎r的值应该是{a:1},然而运行结果却是undefin ...

  2. Googlehack之Github hack

    site:aircrk.com smtpsite:aircrk.com smtp @mail.comsite:aircrk.com root passwordsite:aircrk.com smtp ...

  3. iOS开发工程师面试题(二)

    1.手写冒泡跟插入排序 冒泡排序来源于生活常识,相当于把数组竖起来,轻的向上,重的向下.void bubbleSort(int[] unsorted) { ; i < unsorted.Leng ...

  4. iOS AFNetworking内存泄漏处理方法

    iOS AFN内存泄漏处理方法 细心的你是否也发现AFN的内存泄漏的问题了呢. 在这里给大家提供一个解决AFN内存泄漏的方法. 单例解决AFN内存泄漏 + (AFHTTPSessionManager ...

  5. 12-返回指针的函数&&指向函数的指针

    前言 接下来我只讲指针的最常见用法,比如这一章的内容----返回指针的函数 与 指向函数的指针   一.返回指针的函数 指针也是C语言中的一种数据类型,因此一个函数的返回值肯定可以是指针类型的. 返回 ...

  6. 深入解析Windows操作系统笔记——CH3系统机制

    3.系统机制 微软提供了一些基本组件让内核模式的组件使用: 1.陷阱分发,包括终端,延迟的过程调用(DPC),异步过程调用(APC),异常分发以及系统服务分发 2.执行体对象管理器 3.同步,包括自旋 ...

  7. 实时事件统计项目:优化flume:用file channel代替mem channel

    背景:利用kafka+flume+morphline+solr做实时统计. solr从12月23号开始一直没有数据.查看日志发现,因为有一个同事加了一条格式错误的埋点数据,导致大量error. 据推断 ...

  8. Python检查xpath和csspath表达式是否合法

    在做一个可视化配置爬虫项目时,需要配置爬虫的用户自己输入xpath和csspath路径以提取数据或做浏览器操作.考虑到用户的有时会输入错误的xpath或csspath路径,后台需要对其做合法性校验. ...

  9. SQL Server 2008 R2——以特定符号出现的次数来判断当前内容所在的层次

    =================================版权声明================================= 版权声明:原创文章 禁止转载  请通过右侧公告中的“联系邮 ...

  10. C#调用C/C++动态库 封送结构体,结构体数组

    一. 结构体的传递 #define JNAAPI extern "C" __declspec(dllexport) // C方式导出函数 typedef struct { int ...