現有資料庫存取庫或過於繁瑣(如 Entity Framework),或靈活度不足(難以支援原生 T-SQL 與非同步模式)。本文實作一個零依賴、純 C#的輕量封裝,核心特性:
維護非同步執行緒池、連線字串建構、命令執行排程、結果回呼處理。不可直接實例化,供 DAL 繼承。
開發者自行實作具體的預存程序與 SQL 呼叫方法。範例:
namespace SQLWrapper {
public class DAL : BLL {
public DAL(string server, string db, string user, string pass) {
base.Start(server, db, user, pass); // 初始化連線字串與背景執行緒
}
~DAL() { base.Stop(eStopType.ForceStopAll); } // 釋放資源
// TODO: 在此新增業務方法
}
}
public int MyStoreProcedure(int param1, string param2) {
// 1. 定義回呼資料容器,指定回傳類型:Scalar/Reader/NonQuery
var userData = new StoredProcedureCallbackResult(eRequestType.Scalar);
// 2. 設定參數
userData.Parameters = new SqlParameter[] {
new SqlParameter("@param1", param1),
new SqlParameter("@param2", param2)
};
// 3. 送入執行佇列
if (!ExecuteStoredProcedure("usp_MyStoreProcedure", userData))
throw new Exception("Execution failed");
// 4. 同步等待完成(預設 30 秒逾時,可調整 userData.tsWaitForResult)
if (WaitSqlCompletes(userData) != eWaitForSQLResult.Success)
throw new Exception("Execution failed");
// 5. 取得結果
return userData.ScalarValue;
}
public bool MySQLQuery(int param1, string param2) {
var userData = new ReaderQueryCallbackResult();
string sql = $"SELECT TOP(1) * FROM tbl1 WHERE code = {param1} AND name LIKE '%{param2}%'";
if (!ExecuteSQLStatement(sql, userData)) return false;
if (WaitSqlCompletes(userData) != eWaitForSQLResult.Success) return false;
if (userData.resultDataReader.HasRows && userData.resultDataReader.Read()) {
// 型別安全讀取,自動處理 DBNull
int field1 = GetIntValueOfDBField(userData.resultDataReader["Field1"], -1);
string field2 = GetStringValueOfDBField(userData.resultDataReader["Field2"], null);
DateTime? field3 = GetDateValueOfDBField(userData.resultDataReader["Field3"], null);
}
userData.resultDataReader.Dispose();
return true;
}
// DAL 端:啟動非同步操作並立即回傳控制權
public StoredProcedureCallbackResult MyStoreProcedureASYNC(int param1, string param2) {
var userData = new StoredProcedureCallbackResult(eRequestType.Reader);
userData.Parameters = new SqlParameter[] { ... };
ExecuteStoredProcedure("usp_MyStoreProcedure", userData);
return userData; // 立即回傳,未等待完成
}
// 呼叫端:輪詢檢查狀態
var userData = myDal.MyStoreProcedureASYNC(10, "hello");
while (true) {
switch (myDal.WaitSqlCompletes(userData, 10)) { // 每次等 10ms
case eWaitForSQLResult.Waiting: continue;
case eWaitForSQLResult.Success:
// 處理 userData.resultDataReader
break;
default: throw new Exception("Execution failed");
}
}
Connection Timeout,預設 15 秒userData.tsWaitForResult,預設 30 秒,可調整:userData.tsWaitForResult = TimeSpan.FromSeconds(15);OnDatabaseStatusChanged 事件在連線斷開/恢復時觸發,支援自動重連邏輯| 類型 | 適用場景 | 結果存取屬性 |
|---|---|---|
| ScalarQueryCallbackResult | 單一值查詢 | ScalarValue |
| ReaderQueryCallbackResult | 結果集查詢 | resultDataReader |
| NonQueryCallbackResult | INSERT/UPDATE/DELETE | AffectedRows |
| StoredProcedureCallbackResult | 預存程序(需指定 eRequestType) | 依類型而定 |
這個輕量封裝解決了三大痛點:非同步防阻塞、型別安全讀取、靈活支援預存程序與動態 SQL。完整程式碼可直接整合至專案,無額外 NuGet 依賴,適合追求效能與控制力的專案。