BeeNET 於 v3.4.0 在資料存取層進行了大幅重構,過去的
DbCommandHelper
與SysDb
等輔助類別,現在都統整為單一的DbAccess
類別。
開發者不再需要手動管理DbConnection
、DbCommand
與DbDataReader
,即可輕鬆完成資料操作。此外,DbAccess
也支援批次命令與交易,以及外部連線的整合,讓使用更安全、彈性。本文整理了改版重點與實際使用方式。
DbAccess
:所有資料存取皆透過 DbAccess
,降低耦合度並減少學習成本。DbConnection
、DbCommand
與 DbDataReader
。ExecuteBatch*
可一鍵包交易;任一命令失敗即回滾,並拋出包含失敗索引的例外。Execute(spec, DbTransaction)
/ ExecuteAsync(spec, DbTransaction)
參與外部交易。DbAccess
API 概觀// 內部連線模式:以 databaseId 解析 Provider 與 ConnectionString
var db1 = new DbAccess("HR");
// 外部連線模式:連線與交易生命週期由外部管理
using (var conn = new SqlConnection(connString))
{
conn.Open();
var db2 = new DbAccess(conn); // 外部連線型態與 Provider 對應由框架管理
}
// 同步
DbCommandResult result = db1.Execute(spec);
// 非同步
DbCommandResult resultAsync = await db1.ExecuteAsync(spec, cancellationToken);
var batch = new DbBatchSpec
{
UseTransaction = true,
IsolationLevel = IsolationLevel.ReadCommitted, // 可選
Commands =
{
new DbCommandSpec(DbCommandKind.NonQuery, "INSERT INTO Department(Name) VALUES({0})", "R&D"),
new DbCommandSpec(DbCommandKind.NonQuery, "INSERT INTO Employee(Name, DepartmentId) VALUES({0}, {1})", "Alice", 5)
}
};
// 同步
DbBatchResult batchResult = db1.ExecuteBatch(batch);
// 非同步
DbBatchResult batchResultAsync = await db1.ExecuteBatchAsync(batch, cancellationToken);
若批次第
i
筆失敗:框架會嘗試回滾並拋出
InvalidOperationException($"Failed to execute batch: Command at index {i} failed.", innerException)
,便於快速定位。
using (var conn = new SqlConnection(connString))
{
conn.Open();
using (var tran = conn.BeginTransaction())
{
var db = new DbAccess(conn);
db.Execute(spec1, tran); // 同步
await db.ExecuteAsync(spec2, tran, token); // 非同步
tran.Commit();
}
}
⚠️ 注意:若使用外部交易 (
DbTransaction
),請僅呼叫Execute
/ExecuteAsync
,不應再呼叫ExecuteBatch
。
// Query:直接回傳 List<T>
var list = db1.Query<Employee>(spec);
// QueryAsync:直接回傳 List<T>
var listAsync = await db1.QueryAsync<Employee>(spec, cancellationToken);
var spec = new DataTableUpdateSpec
{
DataTable = table,
InsertCommand = insertSpec,
UpdateCommand = updateSpec,
DeleteCommand = deleteSpec,
UseTransaction = true,
IsolationLevel = IsolationLevel.ReadCommitted // 可選
};
var db = new DbAccess("HR");
int affected = db.UpdateDataTable(spec);
DbCommandSpec
說明DbCommandSpec
是資料庫命令的中介類別:你只需描述「要做什麼」(SQL + 參數 + 命令種類),它就會在執行前依照 DatabaseType 自動轉換成正確的 DbCommand 與 DbParameter。
兩種參數模式
{0}
, {1}
, …(短小、直覺){name}
, {hiredOn}
, …(欄位多時更不易放錯)依 DatabaseType 套用參數前綴
你在 SQL 中寫 {name}
或 {0}
,實際執行時會自動轉換為正確的參數名稱與 DbParameter
。
@name
:name
?name
Stored Procedure 直接傳遞
當 CommandType = StoredProcedure
時,CommandText
不做參數占位符解析,直接用 SP 名稱與參數集合建立命令。
Timeout 規則
CommandTimeout <= 0
以預設 30 秒;若超過全域上限則自動套用上限。
安全性
不論位置或具名參數,都不會做字串拼接;在 CreateCommand()
期間會轉成 DbParameter
,可有效防止 SQL Injection。
DbCommandSpec
使用範例string sql = @"
SELECT EmployeeId,
Name,
HiredOn
FROM Employee
WHERE EmployeeId = {0}";
var command = new DbCommandSpec(DbCommandKind.DataTable, sql, 1001);
var db = new DbAccess("HR");
var employees = db.Query<Employee>(command); // List<Employee>
var spec = new DbCommandSpec(
DbCommandKind.Scalar,
"SELECT COUNT(*) FROM Employee WHERE DepartmentId = {0}",
5
);
var db = new DbAccess("HR");
var result = db.Execute(spec);
int count = Convert.ToInt32(result.Scalar);
var spec = new DbCommandSpec(
DbCommandKind.NonQuery,
"INSERT INTO Department(Name, CreatedOn, IsActive) VALUES({0}, {1}, {2})",
"R&D", DateTime.Now, true
)
{
CommandTimeout = 60 // <=0 使用預設 30 秒;超過全域上限則套用上限(由 setter 處理)
};
var db = new DbAccess("HR");
DbCommandResult r = db.Execute(spec);
Console.WriteLine($"Rows affected: {r.RowsAffected}");
var spec = new DbCommandSpec(
DbCommandKind.NonQuery,
"UPDATE Employee SET Name = {name}, HiredOn = {hiredOn} WHERE EmployeeId = {employeeId}",
new Dictionary<string, object>
{
["name"] = "Alice",
["hiredOn"] = new DateTime(2024, 1, 1),
["employeeId"] = 1001
}
);
var db = new DbAccess("HR");
db.Execute(spec);
var spec = new DbCommandSpec(
DbCommandKind.NonQuery,
"usp_UpdateSalary",
new Dictionary<string, object>
{
["employeeId"] = 1001,
["delta"] = 1000m
}
)
{
CommandType = CommandType.StoredProcedure
};
var db = new DbAccess("HR");
db.Execute(spec);
透過這次的改版,DbAccess
已成為 BeeNET 中唯一且安全的資料存取入口:
開發者現在可以更專注於 SQL 與業務邏輯本身,讓資料存取更直觀、更可靠。
📢 歡迎轉載,請註明出處
📬 歡迎追蹤我的技術筆記與實戰經驗分享
Facebook | HackMD | GitHub | NuGet