将实体附加到上下文失败,因为它已经存在

时间:2014-07-12 16:54:26

标签: entity-framework repository-pattern

我使用Unity of Work和CodeCamper的通用存储库。

更新实体,通用仓库有:

    public virtual void Update(T entity)
    {
        DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
        if (dbEntityEntry.State == EntityState.Detached)
        {
            DbSet.Attach(entity);
        }  
        dbEntityEntry.State = EntityState.Modified;
    }

web api方法:

    public HttpResponseMessage Put(MyEditModel editModel)
    {
        var model = editModel.MapToMyEntity();
        _myManager.Update(model);
        return new HttpResponseMessage(HttpStatusCode.NoContent);
    }

更新方法:

    public void Update(MyEntity model)
    {
        Uow.MyEntities.Update(model);
        Uow.Commit();
    }

在团结工作中:

IRepository<MyEntity> MyEntities { get; }

更新实体时,我收到以下错误:

  

附加信息:附加类型&#39; X&#39;的实体。失败,因为同一类型的另一个实体已具有相同的主键值。       使用&#39;附加&#39;方法或将实体的状态设置为“未更改”#39;或者&#39;修改&#39;如果图中的任何实体具有冲突的键值。       这可能是因为某些实体是新的并且尚未收到数据库生成的键值。       在这种情况下,请使用&#39;添加&#39;方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者&#39;修改&#39;酌情。

  1. 当它是您调用存储库的第一个方法时,更新正常。 (我创建了一个ID已存在于DB中的实体并调用了更新。)

  2. 在更新实体之前获取实体时,更新不起作用。 (例如,我得到一个实体X,将其转换为DTO,然后在UI中更改一些值, 然后调用一个web api,用新的值创建一个实体X. 调用存储库的更新。)

  3. 有什么想法可以避免这种情况吗? 当你有一个CRUD应用程序时,你总是在更新之前调用get。

2 个答案:

答案 0 :(得分:2)

我使用自己的附加方法:

public void Attach<E>(ref E entity)
{
    if (entity == null)
    {
        return;
    }

    try
    {
        ObjectStateEntry entry;
        bool attach = false;
        if (ObjectStateManager.TryGetObjectStateEntry(CreateEntityKey(entitySetName, entity), out entry))
        {
            attach = entry.State == EntityState.Detached;

            E existingEntityInCache = (E)entry.Entity;
            if (!existingEntityInCache.Equals(entity))
            {
                existingEntityInCache.SetAllPropertiesFromEntity(entity);
            }
            entity = existingEntityInCache;
        }
        else
        {
            attach = true;
        }
        if (attach)
            objectContext.AttachTo(entitySetName, entity);
    }
    catch (Exception ex)
    {
        throw new Exception("...");
    }
}

答案 1 :(得分:0)

我有同样的问题。问题出在混合背景下。在context1中从DB读取实体时。然后,如果您可以使用contex2(具有自己的实体缓存的相同上下文的其他实例)更新此实体。这可能会引发异常。

请检查参考资料:

通过context1: 从DB

读取带有引用的entity2的entity1

通过context2: 从DB读取entity2。然后更新entity1(从context1引用entity2)。

当您尝试将带有引用的entity2的entity1附加到context2时,抛出异常,因为entity2已存在于context2中。

解决方案仅使用一个上下文进行此操作。