隨著 .NET Framework 2.0 推出,ADO.NET 引入 DbProviderFactory、DbConnection、DbCommand 等抽象基類,使資料庫無關程式設計成為可能。本文分享一個重構升級的資料存取元件,支援多資料庫、參數化查詢、事務、錯誤日誌等實用功能。
web.config 定義預設提供者與連線字串。<appSettings>
<add key="DataType" value="1" /> <!-- 1=SqlServer, 2=OleDb, 3=Odbc -->
</appSettings>
<connectionStrings>
<add name="ConnStr" connectionString="Data Source=.;Initial Catalog=Northwind;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
為避免單一巨大類別實例化浪費,採用 部分類別 將功能拆分為獨立管理器,按需載入:
public partial class DataAccessHelper : DbBase
{
// 三大管理器,初始為 null
public ParameterManager ParameterMgr;
public TransactionManager TranMgr;
public WebStructManager WebStructMgr;
// 延遲初始化參數管理器
public void LoadParameter()
{
if (ParameterMgr == null) ParameterMgr = new ParameterManager();
else ParameterMgr.ClearParameters();
ParameterMgr.Dal = this; // 反向引用,操作底層 Command
}
}
public class ParameterManager
{
public DataAccessHelper Dal; // 持有主類別引用
public void AddParameter(string name, int value)
{
DbParameter p = Dal.CreateParameter(name);
p.DbType = DbType.Int32; p.Value = value;
Dal.Command.Parameters.Add(p);
}
// 其餘型別多載...
}
設計考量:雖形成循環引用,但受控於單一實例生命週期,不會造成記憶體洩漏。此模式類似「策略模式」與「建造者模式」的結合。
初嘗試用靜態 Dictionary<string, DbParameter> 快取原型,發現第二次取得的竟是同一實例(靜態欄位共享)。改用 switch 依提供者型別 new 具體參數類別:
public DbParameter CreateParameter(string name)
{
DbParameter p = null;
switch (this.DataType)
{
case "1": p = new SqlParameter(); break;
case "2": p = new OleDbParameter(); break;
case "3": p = new OdbcParameter(); break;
}
p.ParameterName = name;
return p;
}
利用靜態建構子一次性載入提供者組件、快取 DbProviderFactory 實例,提升效能。
var dal = new DataAccessHelper();
string name = dal.ExecuteScalar("SELECT ProductName FROM Products WHERE ProductID=1");
string[] row = dal.ExecuteRow("SELECT * FROM Products WHERE ProductID=2");
DataTable dt = dal.ExecuteTable("SELECT * FROM Products WHERE ProductID=3");
dal.Dispose();
dal.LoadParameter();
dal.ParameterMgr.AddParameter("@ProductName", "測試產品", 40);
dal.ParameterMgr.AddParameter("@SupplierID", 23);
dal.ParameterMgr.AddParameter("@UnitPrice", 2.34m);
// ... 其他參數
dal.ParameterMgr.ExecuteNonQuery("Proc_AddProduct");
// 查詢剛新增的資料
DataRow newRow = dal.ExecuteRow("SELECT TOP 1 * FROM Products ORDER BY ProductID DESC");
string accessConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\\data.mdb;";
var dal2 = new DataAccessHelper("2", accessConn); // 傳入型別與連線字串
DataTable dt = dal2.ExecuteTable("SELECT * FROM Manage_Table");
DataAccessHelper.cs:主類別,繼承 DbBaseDbBase.cs:核心實作(連線、命令、事務、日誌)ParameterManager.cs、TransactionManager.cs、WebStructManager.csCommonUtility.cs:型別對照、命名轉換工具此元件在多個專案驗證穩定,兼顧效能與開發效率。未來可擴充:
ExecuteReaderAsync 等)完整原始碼與測試專案:下載連結