首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

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; }
}

各資料庫連線類別皆繼承 DbConnection:

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)可自行擴充。

逐步設計:從工廠模式轉向泛型與委派

常用操作:doCreateConnection、doCreateCommand、doCreateDataAdapter、doFillCommand 等。

嘗試 1:泛型基底驅動類別

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 建構子不統一(如 SqlDataAdapter(SqlCommand)),不同命令類型(增刪查改)需分開處理,不夠簡潔。

嘗試 2:以委派封裝可變邏輯

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);

將原本基礎方法分解,抽出核心邏輯設計成委派。範例:

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);
    PopulateCommand(_c, sql);
    if (!Create) Dispose(true);
    return _d.Tables[0];
  }
}

各資料庫驅動實作委派邏輯

OracleDriver:

public class OracleDriver : BaseDriver {
  public OracleDriver() {
    this.doCreateConnectionEx = () => {
      MaoyaDbConnection mc = new MaoyaDbConnection();
      mc.ConnectionString = this.ConnectionString;
      mc.Create = true;
      mc.doCreateConnection = (conn) => new OracleConnection(conn);
      mc.doCreateFrontConnection = (conn) => this.CreateConnection<OracleConnection>(conn);
      mc.doCreateCommand = (comm) => new OracleCommand(comm);
      mc.doCreateDataAdapter = (sqlcomm) => 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;
    };
  }
}

MySqlDriver:

public class MySqlDriver : BaseDriver {
  public MySqlDriver() {
    this.doCreateConnectionEx = () => {
      MaoyaDbConnection mc = new MaoyaDbConnection();
      mc.ConnectionString = this.ConnectionString;
      mc.Create = true;
      mc.doCreateConnection = (conn) => new MySqlConnection(conn);
      mc.doCreateFrontConnection = (conn) => this.CreateConnection<MySqlConnection>(conn);
      mc.doCreateCommand = (comm) => new MySqlCommand(comm);
      mc.doCreateDataAdapter = (sqlcomm) => 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;
    };
  }
}

融合泛型與委派:提取共通邏輯

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) => 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 因各資料庫差異大,保留在具體驅動類別實作。

結語

本篇示範如何結合泛型與委派簡化多資料庫驅動開發,代碼僅供參考未經測試,功能為部分實作(如交易處理未闡述)。下一篇將探討依賴注入的另類實作方法。

  1. 上一篇文章: No
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved