zoukankan      html  css  js  c++  java
  • 【C#|.NET】从细节出发(二) 善用泛型 委托

    系列文章完成后 源码发布在我的GIT上 https://github.com/dubing/

    文章仅代表个人观点  旨在交流 欢迎讨论


    正文

      按照上一篇结尾留下的话题,本篇着重对数据库操作方面也就是常用工厂模式的地方来进行泛型 委托方向的使用。

      一般大型项目中大家都喜欢依赖注入的方式来数据库操作进行设计,也就是站在面向组件的层次。这里不讨论这样设计的优缺点,我们来看下如果不适用这种方式,只使用委托和泛型如何来良好的替代上面的方案。

      首先分析下sql操作有哪些元素。

        public class BaseDriverParam
        {
            public DbCommand baseCommand { get; set; }
            public DbConnection baseConnection { get; set; }
            public DataAdapter baseDataAdapter { get; set; }
            public DataParameter baseDataParameter { get; set; }
            public DbTransaction baseDbTransaction { get; set; }
            public DbDataReader baseDbDataReader { get; set; }
        }
    

      这里只是一部分,当然也是最常用的部分。选择抽出这些是因为大部分数据库的驱动都支持这些。举个数据库连接的例子

    public sealed class OleDbConnection : DbConnection, ICloneable, IDbConnection, IDisposable
    public sealed class MySqlConnection : DbConnection, ICloneable
    public sealed class SqlConnection : DbConnection, ICloneable
    public sealed class SQLiteConnection : DbConnection, ICloneable
    public sealed class OracleConnection : DbConnection, ICloneable
    

      一些特殊的内容例如 DataParameter在 IDbDataParameter中并不满足需求的场合下我们选择自己填充,同样的还有下面所有的SqlCommandData等,因为不是文章主旨想表达的内容就不啰嗦了。

        明白这些,下面我们就开始一步一步设计,数据库的常用操作有哪些doCreateConnection创建链接,doCreateCommand声明操作命令,doCreateDataAdapter创建数据适配器,doFillCommand执行命令等等...

      这里我们做第一个选择,按照工厂模式,这些内容都是分别在各自的类中实现,那么既然我们已经摈弃了这种方案,那么我们该如何设计比较合理,用泛型么,将不同的驱动参数作为可变元素带入统一的方法中,听起来是不错的,我们先来建立方法结构

     public class TBaseDriver<TCommand, TDbConnection, TDataAdapter, TDataParameter, TDbTransaction> : BaseDriver
            where TCommand : DbCommand, new()
            where TDbConnection : DbConnection, new()
            where TDataAdapter : DbDataAdapter, new()
            where TDbTransaction : DbTransaction, new()
            where TDataParameter : DataParameter,new()
    

      然后我们逐一的实现方法,在这过程中我们会发现并不是所有的方法都符合我们的需求,例如DbDataAdapter中,标准的command要分很多种类型,例如增删查改。然后对于DbDataAdapter没有一个标准的构造函数例如public SqlDataAdapter(SqlCommand selectCommand)这种形式。这样对于不同的类型又要分开操作。既然我们要选择最简洁的方法,自然这样的方式我们就先不考虑了。那么我们把眼光再网上抛一层,以方法直接作为可变元素。

            public delegate string ActionDelegate();
            public delegate IConnectionEx CreateConnectionExDelegate();
            public delegate DbCommand CreateCommandDelegate(string dbClause);
            public delegate DbConnection CreateConnectionDelegate(string dbConnection);
            public delegate DbConnection CreateFrontConnectionDelegate(string dbConnection);
            public delegate DbCommand FillCommandDelegate(DbCommand dbCommand, SqlCommandData sqlCD);
            public delegate DataAdapter CreateDataAdapter(DbCommand dbCommand);
    

      然而我们并非笼统的讲所有的方法都抽出,这样也就是失去了文章本来想要表达的意思。这里我们是将原来基础的方法分解,抽出可怜的逻辑设计成委托。举2个简单的例子

           public DbCommand CreateCommand(SqlCommandData sql)
                {
                    DbCommand _c = doCreateCommand(sql.SqlClause);
    
                    myConnection.Open();
                    if (IsTransaction && myTransaction == null)
                    {
                        myTransaction = myConnection.BeginTransaction();
                    }
    
                    if (IsTransaction)
                    {
                        if (myTransaction == null)
                        {
                            myTransaction = myConnection.BeginTransaction();
                        }
                        _c.Transaction = myTransaction;
                    }
                    _c.Connection = myConnection;
                    _c.CommandTimeout = 300;
                    _c.CommandType = sql.CommandType;
    
                    _c = doFillCommand(_c, sql);
    
                    return _c;
                }
    
                public DataTable Query(SqlCommandData sql)
                {
                    using (DbCommand _c = this.CreateCommand(sql))
                    {
                        DataAdapter _s = doCreateDataAdapter(_c);
                        DataSet _d = new DataSet();
                        _s.Fill(_d);
                        PopuloateCommand(_c, sql);
                        if (!Create)
                        {
                            Dispose(true);
                        }
                        return _d.Tables[0];
                    }
                }
    

      那么我们在各自的驱动类中实现这里委托的逻辑,例如oracle的驱动中

    public class OracleDriver : BaseDriver
        {
            public OracleDriver()
            {
                this.doCreateConnectionEx = () =>
                    {
                        MaoyaDbConnection mc = new MaoyaDbConnection();
                        mc.ConnectionString = this.ConnectionString;
                        mc.Create = true;
                        
                        mc.doCreateConnection = (conn) =>
                            {
                                return new OracleConnection(conn);
                            };
                        mc.doCreateFrontConnection = (conn) =>
                            {
                                return this.CreateConnection<OracleConnection>(conn);
                            };
                        mc.doCreateCommand = (comm) =>
                            {
                                return new OracleCommand(comm);
                            };
                        mc.doCreateDataAdapter = (sqlcomm) =>
                            {
                                return new OracleDataAdapter((OracleCommand)sqlcomm);
                            };
                        mc.doFillCommand = (sqlcomm, sql) =>
                            {
                                foreach (DataParameter dp in sql.Parameters)
                                {
                                    OracleParameter p = new OracleParameter();
                                 
                                    p.ParameterName = dp.ParameterName;
                                    p.Size = dp.Size;
                                    p.Direction = dp.Direction;
                                    p.IsNullable = dp.IsNullable;
                                    p.Value = dp.Value == null ? DBNull.Value : dp.Value;
    
                                    sqlcomm.Parameters.Add(p);
                                }
                                return sqlcomm;
                            };
                        return mc;
                    };
    
            }
        }
    

      或者在mysql的驱动中

        public class MySqlDriver : BaseDriver
        {
            public MySqlDriver()
            {
                this.doCreateConnectionEx = () =>
                    {
                        MaoyaDbConnection mc = new MaoyaDbConnection();
                        mc.ConnectionString = this.ConnectionString;
                        mc.Create = true;
                        
                        mc.doCreateConnection = (conn) =>
                            {
                                return new MySqlConnection(conn);
                            };
                        mc.doCreateFrontConnection = (conn) =>
                            {
                                return this.CreateConnection<MySqlConnection>(conn);
                            };
                        mc.doCreateCommand = (comm) =>
                            {
                                return new MySqlCommand(comm);
                            };
                        mc.doCreateDataAdapter = (sqlcomm) =>
                            {
                                return new MySqlDataAdapter((MySqlCommand)sqlcomm);
                            };
                        mc.doFillCommand = (sqlcomm, sql) =>
                            {
                                foreach (DataParameter dp in sql.Parameters)
                                {
                                    MySqlParameter p = new MySqlParameter();
                                 
                                    p.ParameterName = dp.ParameterName;
                                    p.Size = dp.Size;
                                    p.Direction = dp.Direction;
                                    p.IsNullable = dp.IsNullable;
                                    p.Value = dp.Value == null ? DBNull.Value : dp.Value;
    
                                    sqlcomm.Parameters.Add(p);
                                }
                                return sqlcomm;
                            };
                        return mc;
                    };
    
            }
        }
    

      这么写似乎是ok了,但是我们发现各个驱动中还是有很多可以抽出通用的部分,那么我们重回泛型的概念

        public class TBaseDriver<TCommand, TDbConnection, TDataAdapter, TDataParameter, TDbTransaction> : BaseDriver
            where TCommand : DbCommand, new()
            where TDbConnection : DbConnection, new()
            where TDataAdapter : DbDataAdapter, new()
            where TDbTransaction : DbTransaction, new()
            where TDataParameter : DataParameter,new()
        {
           
            public TBaseDriver()
            {
                this.doCreateConnectionEx = () =>
                {
                    MaoyaDbConnection mc = new MaoyaDbConnection();
                    mc.ConnectionString = this.ConnectionString;
                    mc.Create = true;
    
                    mc.doCreateConnection = (conn) =>
                    {
                        var baseConn = new TDbConnection();
                        baseConn.ConnectionString = conn;
                        return baseConn;
                    };
                    mc.doCreateFrontConnection = (conn) =>
                    {
                        return this.CreateConnection<TDbConnection>(conn);
                    };
                    mc.doCreateCommand = (comm) =>
                    {
                        var baseComm = new TCommand();
                        baseComm.CommandText = comm;
                        return baseComm;
                    };
                   
                    mc.doFillCommand = (sqlcomm, sql) =>
                    {
                        foreach (DataParameter dp in sql.Parameters)
                        {
                            TDataParameter p = new TDataParameter();
    
                            p.ParameterName = dp.ParameterName;
                            p.Size = dp.Size;
                            p.Direction = dp.Direction;
                            p.IsNullable = dp.IsNullable;
                            p.Value = dp.Value == null ? DBNull.Value : dp.Value;
    
                            sqlcomm.Parameters.Add(p);
                        }
                        return sqlcomm;
                    };
                    return mc;
                };
    
            }
    
            
        }
    

      这里我们将可以共通的方法抽出,至于doCreateDataAdapter方法我们再各自的驱动类中实现即可。


    题外

      本篇到此结束,所示代码仅供参考未经测试,功能也只是部分,例如事务操作都没有阐述等等。下一篇和大家一起讨论下依赖注入的一些另类实现方法。

     

    原创作品允许转载,转载时请务必以超链接形式标明文章原始出处以及作者信息。
    作者:熬夜的虫子
    点击查看:博文索引
  • 相关阅读:
    《面向对象编程》c++ primer 第15章
    extern的作用(综合网络)
    C程序内存区域分配(5个段作用)
    鼓舞自己的名言
    快速指数算法 和 求逆元算法
    HP Xeon 55xx上GPU的带宽问题
    Ubuntu12.04 安装ibusfbterm0.9.1
    Win7下读写Ext2/Ext3/Ext4文件系统
    fbv安装 为console添加背景图片
    CentOS6/7安装fcitx4.2.5
  • 原文地址:https://www.cnblogs.com/dubing/p/2983102.html
Copyright © 2011-2022 走看看