承接上一講的查詢功能,本講完整實作 ORM 框架的寫入操作,包含 InsertObjects、UpdateObjects、DeleteObjects 三大核心方法,皆採用反射動態組裝 SQL 並搭配參數化查詢,確保安全與效能。
InsertObjects方法接受物件集合與選擇性資料表名稱,流程如下:
TableBindInfo(含資料表名、欄位綁定集合)。FieldBindInfo.ToDataBase() 轉換後的值。INSERT INTO Table (欄位...) VALUES (參數...) SQL 字串,參數佔位符依 NamedParameter 設定為 @Param 或 ?。strLastSQL 快取上一條 SQL,避免重複設定 IDbCommand 結構,僅更新參數值即可執行,大幅提升批次新增效能。ExecuteNonQuery 執行,累計影響筆數並回傳。// 關鍵片段:SQL 組裝與參數綁定
StringBuilder myStr = new StringBuilder("Insert Into " + FixTableName(TableName2) + " (");
StringBuilder myFields = new StringBuilder();
ArrayList values = new ArrayList();
foreach (FieldBindInfo field in table.Fields) {
object v = field.Property.GetValue(obj, null);
if (v == null || DBNull.Value.Equals(v)) continue;
values.Add(field.ToDataBase(v));
if (myStr.Length > 0) { myStr.Append(", "); myFields.Append(", "); }
myStr.Append("?"); // 或 @Param
myFields.Append(FixFieldName(field.FieldName));
}
myStr.Append(") Values (").Append(myFields).Append(")");
// 參數綁定略...
UpdateObjects更新邏輯需構造 SET 子句與 WHERE 條件:
欄位 = 參數 片段,收集轉換後的值。BuildCondition 依 Key=true 的關鍵欄位產生 WHERE 條件1 AND 條件2...,若無關鍵欄位則拋出異常。UPDATE Table SET ... WHERE ...,清除並重建命令參數,執行更新。private string BuildCondition(object obj, ArrayList values) {
StringBuilder mySQL = new StringBuilder();
foreach (FieldBindInfo field in table.Fields) {
if (field.Attribute.Key) {
object v = field.Property.GetValue(obj, null);
if (v == null || DBNull.Value.Equals(v)) throw new Exception("關鍵欄位未指定值");
if (mySQL.Length > 0) mySQL.Append(" And ");
mySQL.Append(FixFieldName(field.FieldName)).Append(" = ?");
values.Add(field.ToDataBase(v));
}
}
if (mySQL.Length == 0) throw new Exception("無法產生查詢條件");
return mySQL.ToString();
}
DeleteObjects刪除較簡單,僅需 WHERE 條件:
BuildCondition 取得條件 SQL 與參數值。DELETE FROM Table WHERE ...。以 Access 2000 Employees 資料表為例,對應實體 DB_Employees 以特性標記對應關係,EmployeeID 標記為 Key=true。
private MyORMFramework CreateFramework() {
OleDbConnection conn = new OleDbConnection();
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
+ Path.Combine(Application.StartupPath, "demomdb.mdb");
conn.Open();
return new MyORMFramework(conn);
}
private void RefreshList(MyORMFramework myWork) {
object[] objs = myWork.ReadAllObjects(typeof(DB_Employees));
ArrayList list = new ArrayList(); list.AddRange(objs);
this.lstName.DataSource = list;
this.lstName.DisplayMember = "FullName"; // 顯示衍生屬性
}
列表選取事件直接將 DB_Employees 實例屬性繫結至右側文字方塊,展示 ORM 物件導向優勢。
InsertObject 成功後 RefreshList。UpdateObject 成功後重新整理。DeleteObject,重新整理列表。所有操作均採 using 區塊確保連線正確釋放,程式碼簡潔直觀。
此 ORM 框架屬輕量級設計,零外部相依,部署極簡單:將專案輸出為 DLL 參考,或直接複製 MyORMFramework.cs 至專案即可使用。
本系列展示如何善用 .NET 反射(程式基因分析)與特性(宣告式標記)構建靈活框架。反射提供執行期型別探測與動態調用能力,特性提供編譯期中繼資料標記,兩者結合實現「約定優於配置」的 ORM 核心邏輯,大幅降低資料存取層開發與維護成本。