ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。
出现问题的显示:
一,我们来探究下这问题出现的原因:
报错代码块,如下
UserInfo us = _iuserInfoBll.GetById("E501BE1F-07CA-4B5F-9801-02862B41AD8B"); us.NickName = "123132";
_iuserInfoBll.Update(us);
查询方法
public virtual T GetById(string id) { return _dbset.Find(id); }
更新方法:
public virtual void Update(T entity) { _dbset.Attach(entity); //这里报错 DataContext.Entry(entity).State = EntityState.Modified; _dataContext.SaveChanges(); }
根据上面我们发现,出现的原因是:我们先执行了查询操作,然后再执行更新操作,那为什么这样会出现问题?
查找下资料发现:这是由于查询之后的数据,EF默认帮我们缓存了起来,放在了DbContext上下文中,我们在修改的时候,执行dbset.Attach(entity);,发现缓存中已存在同一键值,所以会报这个错。
那我们的解决方法是什么呢?
一,在查询的方法中添加AsNoTracking(),不跟踪
List<Alldetails> all = db.Alldetails.AsNoTracking().Where(m => m.Brand == alldetails.Brand).ToList();
二,我们可以重写update方法,看我仓储中的update方法,是以虚方法定义的,则我们可以重写:
///Entity Framework中编辑时错误ObjectStateManager 中已存在具有同一键的对象 /// <summary> /// 由于出现ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象,重写Update解决 /// </summary> /// <param name="entity"></param> /// <returns></returns> public override void Update(UserInfo entity) { var query = DataContext.Set<UserInfo>().Find(entity.UserID); if (query != null) { DataContext.Entry<UserInfo>(query).State = EntityState.Detached; //这个是在同一个上下文能修改的关键 } query.Mobile = entity.Mobile; query.TrueName = entity.TrueName; query.Remark = entity.Remark; DataContext.Set<UserInfo>().Attach(query); DataContext.Entry(query).State = EntityState.Modified; DataContext.SaveChanges(); }
三,根据上面的逻辑,我们是不是可以修改仓储的GetById方法?代码如下:
public virtual T GetById(Guid id) { T t = _dbset.Find(id); DataContext.Entry<T>(t).State = EntityState.Detached; return t; }
public virtual T Get(Expression<Func<T, bool>> where) { return _dbset.AsNoTracking().Where(where).FirstOrDefault<T>(); }
而这也是通过的,通过查询状态和修改为不跟踪
综上:三种方法都可以结果这个问题