ASP.NET MVC項目 Repository層中,Update、Delete總是失敗
another entity of the same type already has the same primary key value
在項目里的Repository層中的涉及到數據的update方法總是報錯,delete時有時也會報錯,報的錯誤是
Attaching an entity of type 'Model.Diary' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
按字面意思看,發生異常的原因在於已經存在了一個實體與要進行操作的實體存在相同的主鍵,相互沖突。
解決方案:
-
查詢時讓EF不要跟蹤
即在使用EF上下文對象查詢數據時添加 AsNoTracking(),顯示聲明不要讓EF跟蹤對象
1 /// <summary> 2 /// 根據指定條件查詢數據 3 /// </summary> 4 /// <param name="whereLambda">查詢條件 Linq表達式 </param> 5 /// <returns>符合條件的數據列表</returns> 6 public virtual List<T> GetListBy(Expression<Func<T, bool>> whereLambda) 7 { 8 return db.Set<T>().Where(whereLambda).AsNoTracking().ToList(); 9 }
-
在進行更新和刪除時首先移除主鍵實體(如果存在)再進行操作
首先檢查是否已經存在相同主鍵實體,如果存在則移除,然后再開始進行更新或刪除處理,由於新增時,主鍵一定不會相同,因此新增數據可以不需要判斷是否存在相同主鍵實體。
1 /// <summary> 2 /// 監測Context中的Entity是否存在,如果存在,將其Detach,防止出現問題 3 /// </summary> 4 /// <param name="entity"></param> 5 /// <returns></returns> 6 private bool RemoveHoldingEntityInContext(T entity) 7 { 8 ObjectContext objContext = ((IObjectContextAdapter)db).ObjectContext; 9 var objSet = objContext.CreateObjectSet<T>(); 10 var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity); 11 object foundEntity; 12 var exists = objContext.TryGetObjectByKey(entityKey, out foundEntity); 13 if (exists) 14 { 15 objContext.Detach(foundEntity); 16 } 17 return (exists); 18 }
1 public virtual int Modify(T model, params string[] proNames) 2 { 3 RemoveHoldingEntityInContext(model); 4 //4.1將 對象 添加到 EF中 5 DbEntityEntry entry = db.Entry(model); 6 //4.2先設置 對象的包裝 狀態為 Unchanged 7 entry.State = EntityState.Unchanged; 8 //4.3循環 被修改的屬性名 數組 9 foreach (string proName in proNames) 10 { 11 //4.4將每個 被修改的屬性的狀態 設置為已修改狀態;后面生成update語句時,就只為已修改的屬性 更新 12 entry.Property(proName).IsModified = true; 13 } 14 //生成sql語句到數據庫執行 15 return db.SaveChanges(); 16 }
Stackflow上也有一篇文章這樣的問題,傳送門
博客園上也有一篇,解決方案,傳送門