首页 > 解决方案 > EntityFramework 更新实体失败 - 无法跟踪

问题描述

我的应用程序遇到了这个已知问题。我用 HasKey 和 HasAlternateKey 尝试了很多更改,甚至 HasIndex、Unique 和 OnModelCreateCreating() 方法的其他变体。我什至重新映射了我的实体,但仍然没有成功!

无法跟踪实体类型“Imoveis”的实例,因为已在跟踪另一个具有键值“{Cod: 91}”的实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

我的 BaseRepository 类的 Update() 方法:

    public T Update(T entity)
    {
        DbContext.Entry(entity).State = EntityState.Modified; <-- Exception happens here
        DbContext.SaveChanges();
        return entity;
    }

如何调用 Update()。这个问题发生在两个电话上。第二次尝试是防止此错误的失败方法:

public Imoveis InsertOrUpdateUniqueName(Imoveis imoveis)
{
    try
    {
        if (imoveis.Cod > 0)
            Update(imoveis);
        else
            Insert(imoveis);
        return imoveis;
    }
    catch (Exception ex)
    {
        if (imoveis.Cod > 0)
        {
            if (ex is DbUpdateException)
            {
                if ((ex.InnerException as SqlException)?.Number == 2627)
                    return UpdateImovelDuplicado(imoveis);
            }
            else if (ex is InvalidOperationException)
            {
                var local = DbContext
                    .Set<Imoveis>()
                    .Local
                    .FirstOrDefault(x => x.Cod.Equals(imoveis.Cod));
                if (local != null)
                    DbContext.Entry(local).State = EntityState.Detached;
                return Update(imoveis);
            }
        }

        throw ex;
    }
}

标签: c#sqlsql-serverentity-frameworkorm

解决方案


解决了!

解决方案:

1 - In MY CASE (a console app), I removed async inserts or updates because I use a singleton DbContext. But this is NOT mandatory and depends on the case. You need to understand the life cycle of your DbContext.

2 - I changed my Update() method to recover and detach the original object from the DbContext Set collection.

This is my new Update() method calling a new DetachLocal() method for generic objects.

public T Update(T entity)
{
    DetachLocal(entity);
    DbContext.SaveChanges();
    return entity;
}

public void DetachLocal(T t)
{
    var keyname = GetIdName(t);
    var keyValue = GetIdValue(t);

    var local = DbContext.Set<T>()
        .Local
        .FirstOrDefault(entry => GetIdValue(entry).Equals(keyValue));
    DbContext.Entry(local).State = EntityState.Detached;
    DbContext.Entry(t).State = EntityState.Modified;
}

Thanks to @Crowcoder and @DavidBrowne-Microsoft for the replies that put me in the way to find this solution.


推荐阅读