程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#及.NET:從細節出發 設計良好的分布式框架(二) 善用泛型 委托

C#及.NET:從細節出發 設計良好的分布式框架(二) 善用泛型 委托

編輯:關於C#

正文

按照上一篇結尾留下的話題,本篇著重對數據庫操作方面也就是常用工廠模式的地方來進行泛型 委托方向的使用。

一般大型項目中大家都喜歡依賴注入的方式來數據庫操作進行設計,也就是站在面向組件的層次。這裡不討論這樣設計的優缺點,我們來看下如果不適用這種方式,只使用委托和泛型如何來良好的替代上面的方案。

首先分析下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();
         }
     // URL:http://www.bianceng.cn/Programming/csharp/201410/45787.htm
         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;
            };
			//URL:http://www.bianceng.cn/Programming/csharp/201410/45787.htm
            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方法我們再各自的驅動類中實現即可。

題外

本篇到此結束,所示代碼僅供參考未經測試,功能也只是部分,例如事務操作都沒有闡述等等。下一篇和大家一起討論下依賴注入的一些另類實現方法。

    No
  1. 下一頁:
Copyright © 程式師世界 All Rights Reserved