正文
按照上一篇結尾留下的話題,本篇著重對數據庫操作方面也就是常用工廠模式的地方來進行泛型 委托方向的使用。
一般大型項目中大家都喜歡依賴注入的方式來數據庫操作進行設計,也就是站在面向組件的層次。這裡不討論這樣設計的優缺點,我們來看下如果不適用這種方式,只使用委托和泛型如何來良好的替代上面的方案。
首先分析下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方法我們再各自的驅動類中實現即可。
題外
本篇到此結束,所示代碼僅供參考未經測試,功能也只是部分,例如事務操作都沒有闡述等等。下一篇和大家一起討論下依賴注入的一些另類實現方法。