zoukankan      html  css  js  c++  java
  • 扩展 DbUtility (1)

    本文原始路径: 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 无与伦比的体验。

  • 相关阅读:
    HDOJ 1207 汉诺塔II
    [转]写代码的小女孩
    POJ Subway tree systems
    HDOJ 3555 Bomb (数位DP)
    POJ 1636 Prison rearrangement (DP)
    POJ 1015 Jury Compromise (DP)
    UVA 10003
    UVA 103 Stacking Boxes
    HDOJ 3530 Subsequence
    第三百六十二、三天 how can I 坚持
  • 原文地址:https://www.cnblogs.com/Ivony/p/3746538.html
Copyright © 2011-2022 走看看