筆記目錄

Skip to content

淺談 Entity Framework 的導覽屬性與外鍵的同步更新

TLDR

  • 導覽屬性同步的前提是相關 Entity 必須處於追蹤(Tracked)狀態。
  • 任何導致 Entity 狀態改變的操作(如 AddRemove 或呼叫 Entry())都會觸發追蹤檢核,進而自動同步導覽屬性。
  • 導覽屬性是否即時同步不影響 SaveChanges() 的執行結果,EF Core 在儲存時會自動進行異動檢核並完成同步。
  • 若僅設定外鍵屬性(Foreign Key)而不觸發追蹤檢核,導覽屬性不會立即更新。
  • 刪除關聯時,使用 main.Subs.Remove(sub) 僅會解除關聯(或刪除多對多關聯記錄),若要刪除子表資料,必須明確呼叫 context.Subs.Remove(sub)

Entity 結構定義

本測試基於 Entity Framework Core 8,定義主表 Main 與子表 Sub 之間的關聯。

csharp
public partial class Main {
    public long Id { get; set; }
    public virtual ICollection<Sub> Subs { get; set; } = new List<Sub>();
}

public partial class Sub {
    public long Id { get; set; }
    public long MainId { get; set; }
    public virtual Main Main { get; set; }
}

導覽屬性與追蹤狀態的關聯性

問題情境:導覽屬性何時會自動同步?

在開發中,開發者常會疑惑修改 Main.SubsSub.Main 後,另一端的屬性是否會立即更新。

  • 未追蹤狀態:若 Entity 處於 Detached 狀態,修改導覽屬性不會觸發任何同步。
  • 僅單邊追蹤:若僅追蹤主表,新增子表至 Main.Subs 時,子表會被自動加入追蹤並同步導覽屬性;反之,若僅追蹤子表,設定 Sub.Main 時,主表也會被同步加入追蹤。
  • 觸發檢核:呼叫 context.Entry(entity) 或執行 SaveChanges() 時,EF Core 會強制進行狀態檢核,此時導覽屬性會自動修正至正確狀態。

TIP

即便 SaveChanges() 執行失敗(例如主鍵衝突),EF Core 仍會完成導覽屬性的同步更新。

外鍵屬性與導覽屬性的同步行為

問題情境:直接修改外鍵屬性(Foreign Key)是否會更新導覽屬性?

當開發者直接賦值 sub.MainId = 1L 時,若該 Entity 尚未被追蹤或未觸發檢核,導覽屬性 sub.Main 不會立即指向對應的物件。

  • 追蹤後修改:若已追蹤 submain,直接修改 sub.MainId 不會立即更新 sub.Main 物件參考。
  • 同步機制:此行為會在呼叫 SaveChanges()Entry() 後,由 EF Core 的變更追蹤器(Change Tracker)自動修正。
  • Find 方法的影響:使用 context.Mains.Find(id) 取得資料時,若該主表已存在於追蹤器中,EF Core 會自動將其與現有的子表關聯起來。

刪除關聯與刪除資料的差異

問題情境:如何正確移除關聯或刪除資料?

開發者常混淆「解除關聯」與「刪除資料」的操作。

  • 刪除資料:必須明確呼叫 context.Subs.Remove(sub),這會將該 Entity 標記為 Deleted,並在 SaveChanges() 時從資料庫移除。
  • 解除關聯:使用 main.Subs.Remove(sub) 僅會解除兩者關聯。
    • 若外鍵屬性允許 null,該外鍵會被設為 null
    • 若為多對多關聯,則僅會刪除聯結表(Join Table)中的關聯記錄,不會刪除實體本身。

結論

  1. 追蹤與同步:導覽屬性同步的前提是兩邊的 Entity 都必須處於追蹤狀態。任何會導致 Entity 狀態改變的操作,均會觸發追蹤狀態的檢核,進而自動同步更新導覽屬性。
  2. 資料庫更新:導覽屬性的同步與否不會影響資料庫的實際更新。即使導覽屬性未同步,當執行 SaveChanges() 時,系統仍會進行 Entity 的異動追蹤檢核,並自動觸發導覽屬性的同步。
  3. 外鍵屬性參與:當 Entity 觸發異動追蹤檢核時,外鍵屬性也會參與同步過程,因此可以使用外鍵屬性來影響導覽屬性的值。
  4. 資料讀取影響:當從資料庫中讀取資料並將其加入追蹤時,相關的本機 Entity 導覽屬性會自動同步更新。

異動歷程

  • 2024-08-12 初版文件建立。