淺談 Entity Framework 中的預設值行為
TLDR
- 當 SQL Server 欄位設有預設值時,若 Entity 屬性值與該型別的 C# 預設值一致,EF Core 在執行
INSERT時可能會忽略該欄位,導致資料庫觸發預設值。 - 建議盡量避免依賴 SQL 預設值,若必須使用,請確保 SQL 預設值與 C# 預設值一致。
- 針對字串型別,建議統一設為
NOT NULL Default ''以處理空值。 - 更新資料時,若屬性值未變更,
SaveChanges()會回傳0,判斷更新成功與否應考慮EntityState.Unchanged的情況。 - 使用
AsNoTracking()查詢後,若手動將EntityState設為Modified,會導致該 Entity 的所有欄位在UPDATE時被強制更新,而非僅更新異動欄位。
TIP
本篇的完整可執行範例:CloudyWing/EfCoreBehaviorSample。
Entity Framework 的預設值寫入行為
什麼情況下會遇到這個問題:當資料庫欄位定義了預設值(Default Value),且開發者在程式中未明確賦值或賦予的值與 C# 預設值相同時。
測試結果顯示,Entity Framework 並非根據「是否設值」來判定異動,而是透過比對「新舊值」來決定是否產生 INSERT 語法。當屬性值與該型別的預設值(如 null 或 0)一致時,EF Core 可能會忽略該欄位,改由資料庫處理預設值。
若使用 EF Core Power Tools 反向工程,針對 bit 等型別產生 bool? 並標記 Required 時,EF Core 可能會產生 DEFAULT VALUES 語法,進而忽略所有欄位。
建議做法:
- 盡量避免在資料庫層級依賴預設值。
- 若必須使用,請確保 SQL 預設值與 C# 程式碼中的預設值邏輯一致。
- 字串型別建議統一設為
NOT NULL Default '',確保null與空字串處理邏輯一致。
更新 Entity 時的狀態判定
什麼情況下會遇到這個問題:在執行 Update 操作時,若 Entity 的屬性值與資料庫現有值完全相同,SaveChanges() 會回傳 0。
當 Entity 屬性值未變更時,EntityState 會保持為 Unchanged,此時不會產生任何 UPDATE 語法。
建議做法: 在 Business Service 的更新邏輯中,應使用以下方式判斷執行結果,避免誤判:
bool isSuccess = context.Entry(entity).State == EntityState.Unchanged || context.SaveChanges() > 0;AsNoTracking 與 EntityState 的副作用
什麼情況下會遇到這個問題:在查詢時使用了 AsNoTracking(),隨後為了更新資料而手動將 EntityState 設為 Modified。
當使用 AsNoTracking() 查詢後,Entity 不會被 Change Tracker 追蹤。若手動將其狀態設為 Modified,EF Core 將無法得知哪些欄位真正發生了變更,導致 UPDATE 語法會更新該資料表的所有欄位,而非僅更新異動欄位。
建議做法:
- 若非必要,請勿濫用
AsNoTracking()。 - 若需更新資料,應使用標準查詢方式讓 EF Core 追蹤變更,這樣產生的
UPDATE語法只會包含已變更的欄位,效能較佳。
異動歷程
- 初版文件建立。
- 補上對應 GitHub 範例專案連結。