【C#|.NET】從細節出發(二) 善用泛型 委托
2013-03-26 18:32 熬夜的蟲子 閱讀(2337) 評論(1) 收藏 舉報系列文章完成后 源碼發布在我的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方法我們再各自的驅動類中實現即可。
題外
本篇到此結束,所示代碼僅供參考未經測試,功能也只是部分,例如事務操作都沒有闡述等等。下一篇和大家一起討論下依賴注入的一些另類實現方法。
![]() |
原創作品允許轉載,轉載時請務必以超鏈接形式標明文章原始出處以及作者信息。 作者:熬夜的蟲子 點擊查看:博文索引 |

浙公網安備 33010602011771號