筆記目錄

Skip to content

Entity Framework 的 Find 與 Single 的選擇

TLDR

  • Find() 會優先搜尋本地快取(Local Cache),若找不到才會發送資料庫查詢。
  • Find() 不支援 Include() 關聯資料預加載。
  • 使用 AsNoTracking() 後,該 DbSet 將無法使用 Find() 方法。
  • Find() 參數為 object[],編譯階段無法檢查主鍵型別與順序,處理複合主鍵時需特別注意。
  • 建議優先使用 Single()SingleOrDefault(),其語意明確且無 Find() 的快取與功能限制。

Find() 方法的運作機制與限制

什麼情況下會遇到這個問題:當開發者需要根據主鍵取得單一實體,且對效能或快取機制有特定考量時。

Find() 方法的定義如下:

csharp
public virtual TEntity? Find (params object?[]? keyValues);

核心特性

  • 優先查詢本地快取Find() 會先檢查 DbContext 的本地快取(包含已 Load、已查詢過或已 Add 的 Entity)。只有在快取中找不到時,才會向資料庫發送 SQL 查詢。
  • 型別檢查限制:由於參數為 object[],編譯器無法驗證傳入的主鍵型別或順序是否正確。在處理複合主鍵(Composite Key)時,若不清楚 ColumnAttribute 或 Fluent API 定義的順序,極易導致執行時錯誤。
  • 不支援關聯載入Find() 無法搭配 Include() 使用,若需要取得關聯資料,必須改用其他查詢方式。
  • AsNoTracking 的衝突:若查詢時使用了 AsNoTracking(),資料不會進入本地快取。此外,若 DbSet 已經設定為 AsNoTracking(),則該 DbSet 將無法呼叫 Find() 方法。

語意與方法選擇建議

什麼情況下會遇到這個問題:當開發者在評估使用 Find()Single()First() 等方法來獲取資料時。

在 Entity Framework 中,方法命名通常隱含了行為準則:

  • Find 開頭:通常在找不到資料時返回 null(或 default)。
  • Get 開頭:通常在找不到資料時拋出異常。

結論與建議

雖然 Find() 在特定情境下能利用本地快取減少資料庫存取,但其限制較多(如無法使用 Include、對 AsNoTracking 的依賴限制)。為了程式碼的可讀性與維護性,建議優先使用 Single()SingleOrDefault()

  • 語意明確Single() 明確表達了「預期只會有一筆資料」的商業邏輯。
  • 功能完整:支援 Include() 進行關聯資料載入,且不受 AsNoTracking() 的限制。
  • 一致性:與 LINQ 查詢語法整合度更高,適合大多數標準的查詢場景。

異動歷程

  • 2024-07-16 初版文件建立。