尝试通过实体框架更新数据库对象时对象已存在错误

Posted

技术标签:

【中文标题】尝试通过实体框架更新数据库对象时对象已存在错误【英文标题】:Object already exists error when trying to update database object via Entity Framework 【发布时间】:2014-06-13 18:48:32 【问题描述】:

我正在使用以下方法尝试使用实体框架更新对象:

public static void UpdateItem(Item updatedObject) 

  using (var context = new DbContext())
  
    context.MyObjectsPropertys.Attach(updatedObject);
    context.Entry(updatedObject).State = EntityState.Modified;
    context.SaveChanges();
  

附件出现错误:

 An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.

如果我尝试将 Attach 调用更改为 Add 调用 (object with same key already exists objectstatemanager),我会得到:

Cannot insert duplicate key in object 'database.Table'. The duplicate key value is (AttributeValue). The statement has been terminated.

我发现了很多关于这个错误的问题,但没有一个答案适用于我的情况:

我也尝试删除“附加”语句,只是按照Error multiple objects with the same key DbContext 中的建议进行状态更改,但这也没有用。

对我来说最令人沮丧的是,这与成功更新解决方案中其他内容的语句序列完全相同。

【问题讨论】:

你能检查出究竟是哪一行引发了错误吗? 【参考方案1】:

您必须检查具有相同键的实体是否已被上下文跟踪并修改该实体而不是附加当前实体:

var trackedEntity = context.MyObjectsPropertys.Find(updatedObject.Id);
context.Entry(trackedEntity).CurrentValues.SetValues(updatedObject);
context.Entry(trackedEntity).State = EntityState.Modified;
context.SaveChanges();

【讨论】:

这行得通。但是为什么它会抛出一次错误,而不是在工作流相同的其他时候呢?缺乏一致性令人抓狂。【参考方案2】:

您必须检索相同的对象,并且从那时起检索到的对象被 DataContext 对象跟踪。 添加肯定会出错,因为键显然存在于字典中。

我认为您可以使用 context.ChangeTracker.Entries() 检索本地实体,然后查找相同的密钥(如果存在)

【讨论】:

【参考方案3】:

我是这样处理的:

    public virtual void Update(TEntity entityToUpdate)
    
        if (_db.Entry(entityToUpdate).State == EntityState.Added)
            return; // just been added leave state as added

        try
        
            _dbSet.Attach(entityToUpdate);
        
        catch (InvalidOperationException ex)
        
            var trackedEntity = _dbSet.Find(GetKeyValues(entityToUpdate));
            if (trackedEntity == null)
                throw;
            if (_db.Entry(trackedEntity).State != EntityState.Unchanged)
                throw;
            _db.Entry(trackedEntity).State = EntityState.Detached;
            _dbSet.Attach(entityToUpdate);
        
        _db.Entry(entityToUpdate).State = EntityState.Modified;
    

    public object[] GetKeyValues(TEntity entity)
    
        var objectContextAdapter = ((IObjectContextAdapter)_db);
        var name = typeof(TEntity).Name;
        var entityKey = objectContextAdapter.ObjectContext.CreateEntityKey(name, entity);
        var result = entityKey.EntityKeyValues.Select(kv => kv.Value).ToArray();
        return result;
    

【讨论】:

以上是关于尝试通过实体框架更新数据库对象时对象已存在错误的主要内容,如果未能解决你的问题,请参考以下文章

当尝试使用selfTracking时,我收到客户端错误

实体框架与集合对象,使用 Automapper,更新时异常

尝试在 Web API Core 中使用 EF Core 在启动时更新数据库时出现“'无法访问已处置的对象”错误

无法获取要更新实体框架中导航属性的关系

如何让实体框架在不保存对象的情况下创建/更新数据库表

实体框架数据库错误