淺談 Entity Framework 中的預設值行為
TLDR
- 當 SQL Server 欄位設有預設值時,若 Entity 屬性值與該型別的 C# 預設值一致,EF Core 在執行
INSERT時可能會忽略該欄位。 - 建議盡量避免依賴 SQL 預設值,若必須使用,應確保 SQL 預設值與 C# 預設值一致。
- 字串型別建議設為
NOT NULL Default ''以統一處理空值與空字串。 - 當更新 Entity 屬性但值未變更時,
SaveChanges()會回傳0,判斷邏輯應改為context.Entry(entity).State == EntityState.Unchanged || context.SaveChanges() > 0。 - 避免在需要更新的場景使用
AsNoTracking(),若使用後手動將狀態設為EntityState.Modified,會導致該 Entity 所有欄位皆被更新。
Entity Framework 的預設值寫入行為
什麼情況下會遇到這個問題:當資料庫欄位設定了 DEFAULT 約束,且開發者在程式碼中未明確賦值(或賦予與 C# 預設值相同的值)時。
測試發現,Entity Framework 並非根據屬性是否有「設值」行為來判定異動,而是透過比對「新舊值」來決定是否將欄位納入 INSERT 語法。當屬性值與該型別的預設值(如 null 或 0)一致時,EF Core 可能會直接忽略該欄位,交由資料庫處理預設值。
WARNING
若使用 EF Core Power Tools 進行反向工程,針對 bit 等特定型別,可能會因產生的 Entity 屬性型別(如 bool?)與 Required 設定不同,導致 INSERT 語法完全忽略該欄位,進而觸發資料庫的預設值機制。
更新 Entity 但值不變的判斷邏輯
什麼情況下會遇到這個問題:在更新操作中,若 Entity 的屬性值與資料庫現有值相同,但開發者仍執行了 SaveChanges()。
當執行更新時,若屬性值未改變,EF Core 會將 EntityState 維持在 Unchanged,此時 SaveChanges() 不會執行任何 UPDATE 指令並回傳 0。
建議做法: 在 Business Service 的更新邏輯中,應考量 Unchanged 的狀態,避免誤判更新失敗:
int changedCount = context.SaveChanges();
bool isSuccess = context.Entry(entity).State == EntityState.Unchanged || changedCount > 0;AsNoTracking 與 EntityState.Modified 的副作用
什麼情況下會遇到這個問題:在需要更新資料的場景中,誤用了 AsNoTracking() 查詢,隨後為了強行更新而手動將狀態設為 EntityState.Modified。
使用 AsNoTracking() 查詢出的 Entity 不受 Change Tracker 管理,若手動將其狀態設為 EntityState.Modified,EF Core 將無法追蹤哪些欄位真正發生了變更,導致產生的 UPDATE 語法會包含資料表中的「所有欄位」,而非僅是變更的欄位。
建議做法:
- 若需進行更新操作,請勿使用
AsNoTracking()。 - 僅在純粹的唯讀查詢場景中使用
AsNoTracking()以提升效能。
異動歷程
- 2025-07-12 初版文件建立。
