EF Core - DbUpdateException
你是否曾在 SaveChanges() 時迎來晴天霹靂,一行紅字 DbUpdateException 打斷了你的程式?這就像在大海航行時,突然撞上一座看不見的暗礁──平時無聲無息,一出事卻攪得你天翻地覆。
這篇文章,我們就來一起潛入這片資料海域,探查六種常見導致 DbUpdateException 的暗礁地形。每一種都有它的風險與成因,但只要理解清楚,就能順利避開,繼續駛向資料的彼岸。
💥 1. 主鍵(Primary Key)衝突,一碼歸一人主鍵(Primary Key)是資料的身份證號。若你試圖插入一筆資料,但主鍵與資料庫中已存在的資料相同,那就如同系統收到兩張一模一樣的身分證,無法分辨誰是誰,只能報錯。
12context.Users.Add(new User { Id = 1 }); // Id = 1 已存在context.SaveChanges(); // boom!
常見原因
手動指定主鍵值,未使用自動遞增。
測試資料未清空。
💥 2. 外鍵(Foreign Key)違反,找不到對應人外鍵(Foreign Key)是資料之間的橋 ...
EF Core - DbUpdateConcurrencyException
想像你和同事一起編輯一份 Google 文件,你正專心致志地輸入「我們應該大力加薪」,正當你按下儲存,結果——對方也在同一秒按下儲存,而他打的是:「大家應該自願減薪來展現團隊精神。」
🙃 到底誰的才算?你打的血汗心聲,還是對方的職場邪教宣言?
這,就是所謂的 並行更新(Concurrency)問題。而 EF Core 的 DbUpdateConcurrencyException 就是在提醒你:「欸欸欸,有人先改過這筆資料囉!」
🌊 Concurrency(並行)Concurrency 指的是「多個流程同時存取並可能修改同一筆資料」的情況,這在多人協作系統中非常常見,例如:
多位使用者同時編輯同一筆訂單或資料。
他們都按下儲存。
如果系統沒有檢查誰先誰後,那麼後儲存的人將會直接覆蓋掉前面的變更。
這會帶來許多潛在問題:
✅ 使用者的更新被悄悄蓋掉,卻毫無察覺
✅ 系統記錄出現矛盾,無法追蹤真實修改者
✅ 使用者困惑:「剛剛不是明明有改成功嗎?」
因此,我們需要一種方法來判斷資料是否在此期間已經被人修改過。這正是 RowVersion 發揮作用的時刻。
...
EF Core - 資料是否存在
「當我們只想確認某人是否出現過,沒必要翻遍整本通訊錄。」
在資料庫的世界裡,我們經常會遇到一個簡單卻重要的問題:資料是否存在?
不論是確認某個用戶是否曾下單、某篇文章是否已發佈,這些判斷存在與否的查詢看似簡單,卻往往決定了系統的效能與延遲。尤其當資料表龐大、條件複雜時,使用錯誤的寫法可能導致嚴重的效能問題。
今天,我們就從 SQL 與 EF Core 的角度,來聊聊「資料是否存在」這件事。
🌊 SQL 寫法:COUNT vs EXISTS如果只是想知道「是否有訂單」,許多人會這樣寫
1234IF (SELECT COUNT(*) FROM Orders WHERE CustomerID = 'ALFKI') > 0BEGIN PRINT '有訂單'END
但其實效能更佳的寫法是使用 EXISTS
1234IF EXISTS (SELECT 1 FROM Orders WHERE CustomerID = 'ALFKI')BEGIN PRINT '有訂單'END
SEL ...
EF Core - InvalidOperationException
程式世界裡最令人頭痛的,從來不是錯誤訊息,而是「有時錯,有時對」的那種模糊不明。你是不是也曾遇過:明明昨天的程式還好好的,今天一跑卻爆了 InvalidOperationException?
這不是你寫錯,而是你不小心跨越了 DbContext 的界線。就像在海上行船,一不小心就漂出了領海,進入無人知曉的風暴。
這篇文章將帶你從根源理解 InvalidOperationException 的幾個常見場景,並透過範例與圖解,一次性釐清觀念,避免未來再被神祕的錯誤訊息追殺。
💥 DbContext 實例重複使用|一艘船不能載兩個船長問題來源當你在多個請求或執行緒間重複使用同一個 DbContext 實例,就可能觸發 InvalidOperationException。為什麼?因為…
❗ DbContext 不是 Thread-Safe 的物件。
它內部維護著實體狀態(Added, Modified, Deleted…),而這些狀態並不是為多執行緒設計的。你讓多個線程同時操控 DbContext,就像讓兩個船長同時掌舵 —— 翻船。
12345678910public class ...
EF Core - TimeoutException (Part 1)
某天早上,監控系統跳出好幾個 TimeoutException,我們小組群組裡只聽到一句:「啊,應該是網路問題吧,再跑一次就好了。」
這句話讓我背脊一涼。
TimeoutException 並不是資料庫在耍脾氣,它是壓力太大在吶喊。這篇文章,要來好好梳理這些 “吶喊” 背後的真正原因。
🌊 查詢資料太多,撐爆記憶體
有時候你只是開個後台報表,卻默默查了幾十萬筆資料。久而久之,伺服器就跟泡麵一樣——泡過頭,膨脹爛掉。
1️⃣ 真的需要全部資料嗎?
商業情境:報表開發初期為求簡便,可能會習慣「全撈」資料來呈現,但實際使用者只會看最近的記錄。
1234var threeMonthsAgo = DateTime.UtcNow.AddMonths(-3);var recentOrders = await dbContext.Orders .Where(o => o.CreatedDate >= threeMonthsAgo) .ToListAsync();
2️⃣ 使用投影(Select)只抓必要欄位
商業情境:畫面僅顯示使用者名稱與註冊時間 ...
EF Core - TimeoutException PART 2
本篇 ~ 繼續 ~ TimeoutException 可能發生的原因及改善方式,從 Lock、Isolation Level、Retry、連線池,到 Change Tracker 與批次處理
🌊 為什麼資料庫會「卡住」?—— 談 Lock
🔒 資料庫為什麼會 Lock?當兩個交易(Transaction)同時存取資料時,為了確保資料一致性,資料庫會自動幫我們上鎖。像是:
其他交易正在修改這筆資料(而還沒提交 Commit)
你要修改的資料已經被排他鎖定
這時候,後來的交易就只能等別人釋放鎖,不然就只能拋錯。等待超過 Command Timeout,就會拋出 TimeoutException 或 SqlException。
關鍵例外訊息可能會有哪些?1234567System.TimeoutExceptionMicrosoft.Data.SqlClient.SqlException常見訊息:Timeout expired. The timeout period elapsed prior to completion of the operation or th ...
EF Core - Logging
在平穩無波的資料操作背後,EF Core 為我們自動生成了大量 SQL 語法。這些語法就像資料的悄悄話,大部分時間默默運作,沒出錯就好。但一旦效能下滑、查詢遲緩,這些悄悄話就需要被「聽見」。
因此,我們需要打開 EF Core 的日誌紀錄機制,看看背後究竟在跑什麼樣的 SQL。
🌊 為什麼要紀錄 EF Core 自動產生的 SQL 命令?EF Core 是一套功能強大的 ORM 框架,幫助我們用物件導向的方式操作資料。但 ORM 所產生的 SQL 並非總是最有效率的選擇。
透過 Logging,我們可以:
檢查 EF Core 實際送出的 SQL 語法
發現不必要的 JOIN 或 WHERE 條件
優化查詢速度(例如加上索引、改用 View 或 Stored Procedure)
這對效能調教與除錯都非常有幫助。
🌊 調整 appsettings.json 的 LogLevel12345678910{ "Logging": { "LogLevel": { "Defa ...
EF Core - 交易的界線
「啊…我有開 TransactionScopeAsyncFlowOption.Enabled 嗎?」「咦?這兩個 Context 是不是不同連線?」「等一下,我是不是跨資料庫了?那 MSDTC 呢?」
交易的邊界,就像洋流與領海,有時你以為你還在安全區,其實早已飄出防線。
這篇筆記,就是一趟從這場 Bug 航行而來的實驗紀錄 —— 我們用四種實際情境來測試 EF Core 的交易能力:
同資料庫、不同 DbContext
跨資料庫
共用連線 vs 不共用連線
TransactionScope vs BeginTransaction
如果你也曾在交易邊界迷航過,歡迎登船。
🧭 實驗開航前:DBContext 的布陣
為了這趟「交易航線實驗」,我們準備了三個 DbContext:
AdventureWorks2022:一個普通的 DbContext。
AdventureWorks2022V2:與 AdventureWorks2022 使用相同的資料庫,但是不同的 DbContext 實例。
NexCommerce_CouponContext:指向另一個資料庫。
123b ...
Dapper vs EF Core
如果資料存取是場人生選擇,那 EF Core 就像「全包式旅行團」:行李、住宿、行程幫你安排好,你只要準時上車;而 Dapper 則像「背包客自由行」:想去哪、怎麼走、要不要迷路,全靠你自己。
在 .NET 的世界裡,EF Core 與 Dapper 是資料存取的兩大門派,一個幫你包辦大小事,一個讓你操控每一行 SQL。
你可能常常陷入這種掙扎:
「欸現在這隻微服務要查一堆訂單、明細、客戶資料,我要不要用 EF?還是會變龜速大怪獸?」「有三層關聯欸,用 Dapper 要手動 map 到哭出來,欄位一多手都斷了吧…」
🌊 ORM
在開發應用程式時,資料通常儲存在資料庫(Database)中,而程式則是用物件(Object)在操作資料。但是資料庫與程式是兩種世界
資料庫用的是「表格」(table)來存資料,C# 用的是「物件」和「類別」
這兩個東西的結構不同、語言不同、邏輯也不同。
👉 ORM(Object-Relational Mapping)本質是什麼?
它是一座橋梁,幫你自動把「資料表」轉成「物件」,也幫你把你操作的物件轉回資料表格式,這個過程就叫做 ...
EF Core - DbContext 生命週期
「這裡的風很大,請小心 DbContext 被吹出作用域。」
開發 ASP.NET Core 應用程式時,你一定碰過這段設定
1services.AddDbContext<MyDbContext>();
這一行註冊你的 DbContext,但你知道它的 生命週期(Lifetime)是什麼嗎?Scoped、Transient 差在哪?又該怎麼選擇?今天我們就來一趟資料庫生命週期的航行。
🌊 EF Core 的預設生命週期:ScopedEntity Framework contexts
By default, Entity Framework contexts are added to the service container using the scoped lifetime because web app database operations are normally scoped to the client request.
簡單來說,EF Core 的 DbContext 預設會註冊成 Scoped,也就是,每個 HTTP Request 會 ...