由于另一个具有相同主键值的相同类型实体已经存在,因此附加类型为“X”的实体失败。

13

错误消息:

附加一个类型为 'FaridCRMData.Models.Customer' 的实体失败,因为另一个具有相同主键值的实体已经存在。 当使用 Attach() 方法或将实体状态设置为“未更改”或“已修改”时,如果图形中的任何实体存在冲突的键值,则可能会发生此情况。这可能是因为一些实体是新的,并且尚未接收到数据库生成的键值。在这种情况下,请使用“Add”方法或“Added”实体状态来跟踪图形,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。

我的代码:

public class FactorController : Controller
{
    public JsonResult SaveFactor(Factor factor,int id)
    {
        if (id > 0)
        {
            bool result = new FactorService.BaseService.Update(factor);
            return new JsonResult() { Data = result };
        }

    }
}

FactorService.BaseService.cs:

public bool Update(TEntity entity)
{
    var entry = context.Entry(entity);
    if (entry.State == EntityState.Detached || entry.State == EntityState.Modified)
    {

        context.Set<TEntity>().Attach(entity);// Error Is Here
        entry.State = EntityState.Modified;
        context.SaveChanges();
    }
    return true;
}

1
问题在于该对象已经以此 Id 存在于上下文中。如果已经存在,您就不需要再将其 附加(Attach)到上下文中。 - Aggromonster
5个回答

21

我相信你在更新之前可能已经调用了Select。默认情况下,DBContext在提取(选择)记录时会缓存它们,因此在获取记录时,使用" AsNoTracking()" 在您的select调用中。


1
这是最合适的答案。 - Prashant Gupta
1
这就是我整天在寻找的答案!以下是我的示例,以帮助其他人找出它应该放在哪里。var recordToUpdate = db.Reservations.AsNoTracking().Single(x => x.ID == reservation.ID); 接下来的几行是记录中我不想在编辑页面上更新的值,然后是 db.Entry(reservation).State = EntityState.Modified;db.SaveChanges(); - Jamie

6

您是否尝试在将实体附加到上下文之前将其标记为已修改?

像这样:

public bool Update(TEntity entity)
{
    var entry = context.Entry(entity);
    if (entry.State == EntityState.Detached || entry.State == EntityState.Modified)
    {
        entry.State = EntityState.Modified; //do it here

        context.Set<TEntity>().Attach(entity); //attach

        context.SaveChanges(); //save it
    }
    return true;
}

欢迎帮助你!EF的神秘之处;-) - federico scamuzzi
1
如果第一条语句(entry.State = EntityState.Modified)成功,那么该实体将被附加。EF如何设置未附加实体的状态?为什么要使用 || entry.State == EntityState.Modified?将“Modified”实体设置为“Modified”的意义是什么?换句话说,只有将实体的状态设置为“Modified”就足够了。检查实体是否未被“删除”更有用。 - Gert Arnold
由于某些原因,我需要将 State=EntityState.Modified 移动到函数的开头,在实际修改任何内容之前。如果它在 SaveChanges 附近的末尾,每次都会崩溃。 - James L.

2
如果在更新操作期间选择一些数据(就像我遇到的问题一样),请不要使用.ToList().Find()....而是使用as IQueryable,然后使用.AsNoTracking().....问题解决了。最初的回答。

1

您需要先分离本地版本,然后进行更新过程

var localEntity = dbContext.Set<theModel>()
    .Local
    .FirstOrDefault(f => f.Id == theModel.Id);
if (localEntity != null)
{
    dbContext.Entry(localEntity).State = EntityState.Detached;
}
dbContext.Entry(appModel).State = EntityState.Modified;

0
尝试为您要更新的实体更改状态,然后调用SaveChanges()函数。
public bool Update(TEntity entity)
{

        context.Entry(entity).State = System.Data.EntityState.Modified;
        context.SaveChanges();
        return true;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接