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>();
        }

而这也是通过的,通过查询状态和修改为不跟踪

综上:三种方法都可以结果这个问题

原文地址:https://www.cnblogs.com/May-day/p/5379246.html