首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

深入掌握 ADO.NET Entity Framework 核心:ObjectContext 完整操作指南

     編輯:關於.NET

前言

在 ADO.NET Entity Framework (EF) 的架構中,ObjectContext 扮演著核心角色,它是管理實體物件生命週期、追蹤變更、處理持久化以及協調資料庫交易的中心樞紐。本文將系統性地剖析 ObjectContext 的核心功能,涵蓋實體增刪改查、狀態管理、變更持久化、併發控制與交易處理等關鍵主題,並輔以實戰代碼範例,助您深入掌握 EF 開發的精髓。

一、 實體資料操作:從新增到分離的完整週期

1.1 AddObject:將實體納入追蹤

新建的實體物件初始狀態為 EntityState.Detached(游離狀態),呼叫 AddObject 或強型別的 AddTo[EntitySet] 方法後,實體狀態轉為 EntityState.Added,標記為待插入資料庫。

using (var context = new MyContext())
{
    var entity = new MyTab { ID = 10, Name = "wxwinter" };
    Console.WriteLine(entity.EntityState); // Detached

    context.AddToMyTab(entity); // 或 context.AddObject("MyTab", entity);
    Console.WriteLine(entity.EntityState); // Added

    context.SaveChanges();
}

1.2 DeleteObject:標記刪除而非移除

DeleteObject 並不會從集合中移除實體,而是將其狀態標記為 EntityState.Deleted。下次呼叫 SaveChanges 時,EF 會發送 DELETE 命令。

var entity = context.MyTab.First(p => p.ID == 1);
context.DeleteObject(entity); // 狀態變為 Deleted
context.SaveChanges();

1.3 Detach:讓實體脫離管理

呼叫 Detach 可將實體從 ObjectContext 移除,狀態回歸 Detached。此後對實體的任何修改將不再被追蹤。

1.4 直接修改與 ApplyPropertyChanges

  • 直接修改:對已追蹤實體的屬性賦值,EF 自動偵測並將狀態標記為 Modified。
  • ApplyPropertyChanges:適用於「離線實體」更新場景。將一個不在 Context 中的實體(含最新值)套用至 Context 中對應鍵值的實體上,自動將目標實體標記為 Modified。前提是 Context 中必須已存在該鍵值的實體。

1.5 Attach / AttachTo:重新附加離線實體

當實體經過序列化傳輸(如 WCF、Web Service)回到伺服器端,需重新附加至 Context 才能持久化變更。Attach 附加後狀態為 Unchanged,若需更新必須手動標記修改屬性(SetModifiedProperty),這比 ApplyPropertyChanges 更精確,可僅更新特定欄位。

var detachedEntity = new MyTab { ID = 1 };
detachedEntity.EntityKey = context.CreateEntityKey("MyTab", detachedEntity);
detachedEntity.Name = "Updated";

context.Attach(detachedEntity);
var ose = context.ObjectStateManager.GetObjectStateEntry(detachedEntity);
ose.SetModifiedProperty("Name"); // 僅標記 Name 為修改
context.SaveChanges();

1.6 EntityKey 與鍵值查詢

EntityKey 封裝實體集名稱與鍵值,是實體在 Context 中的唯一身分證。可透過 CreateEntityKey 建立,再用 GetObjectByKey 或 TryGetObjectByKey 快速取得實體,避免重複查詢資料庫。

1.7 CreateQuery:以 ESQL 執行動態查詢

支援 Entity SQL (ESQL) 字串查詢,回傳 ObjectQuery<T>,適合動態組裝查詢條件的場景。

二、 狀態管理機制:ObjectStateManager 深度解析

2.1 EntityState 五大狀態枚舉

狀態說明
Detached實體不受任何 Context 管理
Unchanged自上次 AcceptChanges 後未變更
Added已加入 Context,待插入資料庫
Deleted標記刪除,待從資料庫移除
Modified屬性值已變更,待更新資料庫

2.2 ObjectStateManager:狀態追蹤的核心

透過 ObjectStateManager 可存取所有受管理實體的 ObjectStateEntry,提供以下關鍵方法:

  • GetObjectStateEntry(entity/EntityKey):取得單一實體的狀態條目
  • TryGetObjectStateEntry(...):安全嘗試取得,避免拋出異常
  • GetObjectStateEntries(EntityState):依狀態篩選實體集合(如取得所有 Added 實體)
  • ObjectStateManagerChanged 事件:監聽實體加入、移除、重新整理等集合變更動作

2.3 ObjectStateEntry:掌握實體變更細節

每個 ObjectStateEntry 暴露豐富的屬性與方法:

  • CurrentValues / OriginalValues:分別取得目前值與載入時的原始值(僅 Unchanged/Modified/Deleted 才有 OriginalValues)
  • GetModifiedProperties():回傳已修改屬性名稱集合
  • SetModified() / SetModifiedProperty(name):手動標記實體或特定屬性為 Modified,配合 Attach 使用極為強大
  • AcceptChanges():接受變更,將狀態轉為 Unchanged,並以 CurrentValues 覆寫 OriginalValues。注意:Deleted 實體呼叫此方法會被 Detach
  • Delete():等同於 Context.DeleteObject,標記為 Deleted

三、 變更持久化:SaveChanges 多重模式與事件

3.1 SaveChanges 三種簽章

方法行為
SaveChanges()等同 SaveChanges(true):持久化後呼叫 AcceptAllChanges,所有狀態歸為 Unchanged
SaveChanges(true)持久化 + AcceptAllChanges
SaveChanges(false)僅持久化至資料庫,保留原有狀態(Added/Modified/Deleted 不變),適合需重試或分散式交易場景

3.2 SavingChanges 事件

在實際發送 SQL 指令前觸發,可在此攔截驗證、記錄審計日誌或修改實體值。

3.3 AcceptAllChanges

將 Context 中所有實體狀態強制設為 Unchanged,同步 OriginalValues。等同於對每個 ObjectStateEntry 呼叫 AcceptChanges()。

四、 連線與中繼資料屬性

  • DefaultContainerName:指定預設實體容器名稱(對應 EDMX 中的 EntityContainer)
  • Connection:底層 EntityConnection,可控制開啟/關閉、交易綁定
  • CommandTimeout:SQL 命令逾時秒數
  • MetadataWorkspace:存取 CSDL/SSDL/MSL 中繼資料,進階動態模型操作時使用

五、 併發控制與資料重新整理

5.1 併發模式:Fixed (開放式併發)

在 EDM 設計器中將屬性的 ConcurrencyMode 設為 Fixed,EF 會在 UPDATE/DELETE 的 WHERE 子句中加入該欄位原始值比對。若資料庫值已被他人修改,拋出 OptimisticConcurrencyException。

5.2 快取不會自動更新

不同 Context 實例擁有獨立快取。Context1 修改並存檔後,Context2 重新查詢才能看到最新資料,否則仍持有舊版本。

5.3 Refresh 方法:解決併發衝突的兩種策略

模式行為適用場景
StoreWins (資料庫優先)以資料庫最新值覆寫本地修改,放棄使用者變更管理員強制同步、唯讀資料重新整理
ClientWins (客戶端優先)保留本地修改,並更新 OriginalValues 為資料庫最新值,後續 SaveChanges 不再報併發錯誤使用者堅持提交變更、最後寫入者勝出
// 捕獲異常後處理
try { context.SaveChanges(); }
catch (OptimisticConcurrencyException)
{
    context.Refresh(RefreshMode.ClientWins, entity); // 或 StoreWins
    context.SaveChanges();
}

// 也可預先 Refresh 再 SaveChanges,避免異常
context.Refresh(RefreshMode.ClientWins, entity);
context.SaveChanges();

六、 交易處理:從隱性到分散式

6.1 單一 SaveChanges 的隱性交易

單次 SaveChanges 內的所有 INSERT/UPDATE/DELETE 自動包裹在一個資料庫交易中,任一失敗全盤回滾。

6.2 跨 Context / 跨 SaveChanges 需顯式交易

  • DbTransaction:基於單一連線,手動 BeginTransaction/Commit/Rollback。注意:兩個 Context 共用同一連線交易易發生死結。
  • TransactionScope (System.Transactions):推薦方案。支援跨多個 Context、跨資料庫、甚至跨資源管理員 (MSDTC) 的分散式交易,自動處理提升與完成。
using (var scope = new TransactionScope())
{
    using (var ctx1 = new MyContext()) { ctx1.AddTo...(); ctx1.SaveChanges(); }
    using (var ctx2 = new MyContext()) { ctx2.AddTo...(); ctx2.SaveChanges(); }
    scope.Complete(); // 全部成功才提交
}

結語

ObjectContext 是 Entity Framework 3.5/4.0 時代的核心類別(EF Core 已改為 DbContext),掌握其狀態管理、變更追蹤、併發與交易機制,是構建健壯、高效能資料存取層的關鍵。希望本文詳細的分類說明與代碼範例,能成為您 EF 開發路上的得力參考。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved