我知道這個問題已經被問過好幾次了,大多數人直接建議解決問題中提出的代碼段,但我真的很想知道這個錯誤背后的核心原因,因為我們在哪種情況下會得到這個錯誤?我在許多問題中看到人們給出了可以解決問題的不同答案,但我仍然沒有找到此錯誤的確切原因。我已經讀到這是由于 EF Core 的跟蹤行為,但究竟是什么行為導致了這個問題?
一些小代碼示例將不勝感激。謝謝。
uj5u.com熱心網友回復:
嗯,我已經除錯了 EF Core 的這部分。ChangeTracker 中至少有兩項檢查物體是否存在。
- 通過物體參考查找條目,如果找到 - 一切正常。
- 按物體的主鍵查找條目,如果找到了 - 你有這個例外。
如果第二次檢查通過,附加物體將在兩個字典中注冊(如果您有多個鍵,則通過鍵查找條目將是附加字典)。
這是簡化的解釋,但它解釋了為什么最好先查看已跟蹤的物體,然后決定使用哪個條目來避免此類例外。
uj5u.com熱心網友回復:
本質上,原因就在錯誤訊息中。
當您使用 EF 從資料庫下載某些內容時,除非您告訴它不要這樣做,否則它將跟蹤它下載的物體。無論你對得到的物體做什么,EF 也會記住它。這不是唯一的原因,但一個非常明顯的原因是,當需要保存更改時,它使生活變得更加輕松:
var u = db.Users.FirstOrDefault(x => x.Name == "John");
u.Name = "Jim";
db.SaveChanges();
如果 EF 真的只是下載了資料,制作了一個User并移交了它并且不保留任何記憶體,那么SaveChanges它將無法作業;它必須看起來像
db.SaveChanges(u);
即您必須將更改后的資料回傳。如果您想使用樂觀并發,這也會帶來更多的復雜性,因為這通常通過將 in-db 值與最初下載的值進行比較來了解其他人是否在您擁有物件的時間內編輯了該資料庫.
樂觀的保存可能如下所示:
UPDATE user SET name = 'Jim' WHERE id = 123 and name = 'John'
我們知道用戶擁有的原始名稱(“John”)包含在更新查詢中。如果沒有其他人更改用戶名,那就太好了,更新將成功,因為 WHERE 子句將為真。如果有人做了重新命名這個用戶,我們之前做過,那么更新失敗(更新0行),我們可以對付它。
如果 EF 失去了對舊名稱的所有記憶,我們將無法做到這一點;一個User物件只有一個簡單的字串屬性,Name因為"John"在我們用"Jim"..用戶是時候將其更新回資料庫
公平地說,在 EF 背景關系的背景中確實有很多聰明的東西,遠遠超出我們看到的內容(即“用戶物件”)并記住它看到的物件和關于它們的資料,它們的原始值、當前值、是否添加/更新/洗掉它們等對于能夠有效運行至關重要
問題出現的地方是,如果您執行一些操作,例如創建另一個User具有與 EF 已知的主鍵相同的主鍵的全新物體,并嘗試將其附加到 EF 的物件存盤:
var u1 = db.Users.FirstOrDefault(x => x.Name == "John"); //EF now knows user 123
...
var u2 = new User { Id = 123, Name = "Mary"}
db.Users.Add(u2); //EF already knows user 123; John
如果 EF 知道兩個 ID 都是 123 的用戶,它就無法確定哪個記錄是真實的記錄,因此它拒絕開始記住另一個具有它已經知道的 ID 的不同用戶。在上面的代碼中,兩個用戶是記憶體中不同位置的不同物件,他們共享相同的 ID。這無法映射回資料庫
可能還應該指出的是,如果您已經告訴 EF ID 是由資料庫生成的,那么在執行 Add 時為 ID 設定的內容根本無關緊要:EF 將知道它是一個添加的物體,它將當它被保存時,它的 ID 被資料庫覆寫,這樣如果你的“臨時”與現有的沖突,你就不會得到“另一個具有相同 ID 的實體”錯誤
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/313328.html
上一篇:EFCore1:1關系?
