我有一個問題,我無法將物體附加到 DBContext,盡管它顯示其 Enity.State 為分離。
我使用 DBContext 獲取物體,然后處理然后進行一些更改并嘗試使用新 DBContext 保存這些新更改,因此顯然新 DBContext 沒有將這些物體視為附加,因此我需要將它們附加到它。
當我嘗試使用下面的代碼附加物體時
db.Receipts.Attach(receipt);
我得到那個錯誤
“ObjectStateManager 中已存在具有相同鍵的物件。ObjectStateManager 無法跟蹤具有相同鍵的多個物件”
我嘗試在第一次 DBContext 提取中使用 AsNoTracking() 獲取物體,但它仍然顯示相同的錯誤。
我嘗試使用附加 db.Entry(receipt).State = System.Data.Entity.EntityState.Modified;
也嘗試使用 objectContext.ObjectStateManager.ChangeObjectState(receipt, System.Data.Entity.EntityState.Modified);
仍然有同樣的問題。
我想提一下,我使用的是舊的 .Net Framework 4.0 和 Enity Framework 6.0。
任何幫助將非常感激。
uj5u.com熱心網友回復:
您可以執行以下操作以獲取對新 DBContext 的更改:
System.Data.Entity.Core.Objects.ObjectContext objectContext = ((IObjectContextAdapter)db).ObjectContext;
string entitySetName = objectContext.CreateObjectSet<Receipts>().EntitySet.Name;
objectContext.ApplyCurrentValues<Receipts>(entitySetName, receipt);
編輯:您必須首先從資料庫中加載原始物體(如果尚未加載):
IDbSet<Receipts> dbset = db.Set<Receipts>();
var dbReceipt = dbset.Find(id)
uj5u.com熱心網友回復:
當在回圈中處理行并使用相關物體時,通常會出現此錯誤,尤其是在這些物體已被序列化/反序列化或作為修改程序的一部分進行克隆的情況下。
假設我從 DbContext 加載了一個參考同一團隊的玩家串列。
Player (Id: 1, Name: George, TeamId: 10) [REF 101]
Player (Id: 2, Name: Simon, TeamId: 10) [REF 102]
Team (Id: 10, Name: Jazz) [REF 103]
George 和 Simon 都會急切地加載他們的團隊,這兩個團隊都將參考一個團隊物體 [REF 103]。
如果我們分離這些,然后打開一個新的 DbContext 并重新附加:
context.Players.Attach(player1);
context.Teams.Attach(player1.Team);
context.Players.Attach(player2);
context.Teams.Attach(player2.Team);
這應該按預期作業。即使我們兩次附加同一個團隊,它也是相同的參考,EF 將跳過第二次呼叫,因為參考已經附加。警告:自從我使用 EF4 以來已經有很長時間了,因此這種行為可能會有所不同,已通過 EF6 進行了驗證。在附加之前,您可能需要檢查 DbContext 以查看物體是否已分離:
if(context.Entry(player1).State == EntityState.Detached)
context.Players.Attach(player1);
if(context.Entry(player1.Team).State == EntityState.Detached)
context.Teams.Attach(player1.Team);
if(context.Entry(player2).State == EntityState.Detached)
context.Players.Attach(player2);
if(context.Entry(player2.Team).State == EntityState.Detached)
context.Teams.Attach(player2.Team);
現在,如果這些物體通過序列化程式反饋并回傳(例如使用 ASP.Net 表單提交或 Ajax 呼叫等完成),我們回傳的是帶有新參考的斷開連接的新物體,但有一個關鍵區別:
Player (Id: 1, Name: George, TeamId: 10) [REF 201]
Player (Id: 2, Name: Simon, TeamId: 10) [REF 202]
Team (Id: 10, Name: Jazz) [REF 203]
Team (Id: 10, Name: Jazz) [REF 204]
George 將參考一個團隊,在本例中為 REF 203,而 Simon 將參考同一團隊的一個實體,但 REF 204。2 個包含相同資料的實體。
當我們將 Player 1 [REF 201]/w Team 10 [REF 203] 附加到新的 DbContext 時,一切都按預期進行。但是,當我們附加玩家 2 時,我們將收到玩家 2 的團隊參考的錯誤:
context.Players.Attach(player1);
context.Teams.Attach(player1.Team);
context.Players.Attach(player2);
context.Teams.Attach(player2.Team); // <-- Boom
DbContext 將根據玩家 1 的參考跟蹤團隊 #10。即使檢查附加/分離狀態也無濟于事,因為這些是不同的參考。
為了解決這個問題,我們需要在附加之前始終檢查 DbContext 中是否存在現有的跟蹤參考。這可以通過查詢LocalDbSet的屬性來完成。這不會影響資料庫,它只會檢查本地跟蹤的參考。處理分離物體的安全方法:
var trackedTeam = context.Teams.Local.SingleOrDefault(x => x.Id == player1.Team.Id);
if (trackedTeam == null)
context.Teams.Attach(player1.Team);
else
player1.Team = trackedTeam;
var trackedPlayer = context.Players.Local.SingleOrDefault(x => x.Id == player1.Id);
if (trackedPlayer == null)
context.Players.Attach(player1);
trackedTeam = context.Teams.Local.SingleOrDefault(x => x.Id == player2.Team.Id);
if (trackedTeam == null)
context.Teams.Attach(player2.Team);
else
player2.Team = trackedTeam;
trackedPlayer = context.Players.Local.SingleOrDefault(x => x.Id == player2.Id);
if (trackedPlayer == null)
context.Players.Attach(player2);
In the case where a DbContext is already tracking an entity, you may need additional code to compare and copy values across from the untracked copy to the tracked existing instance. Working with detached entities safely with references can be rather clumsy process.
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/313324.html
