首页 文章

无法跟踪实体类型的实例...因为已经跟踪了具有相同密钥的此类型的另一个实例

提问于
浏览
1

给定使用Entity Framework Core和SQL数据库的ASP.NET Core webapp .

尝试更新数据库中的实体时,一个绝对简单的操作就是抛出此异常 . 首先注意到 生产环境 中的错误报告 .

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(string id, [Bind("Group")] EditViewModel model)
{
    if (id != model.Group.Id) return NotFound();

    if (!ModelState.IsValid) return View(model);

    _context.Update(model.Group);
    await _context.SaveChangesAsync();

    return RedirectToAction("Index");
}

行被抛出异常: _context.Update(model.Group);

InvalidOperationException:无法跟踪实体类型“Group”的实例,因为已经跟踪了具有相同键的此类型的另一个实例 . 添加新实体时,对于大多数密钥类型,如果未设置密钥,则将创建唯一的临时密钥值(即,如果为密钥属性指定了其类型的默认值) . 如果要为新实体显式设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突 . 附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文 .

显然没有其他实例 . 当我在该行上使用断点停止代码并展开 _context.Group 对象的Results属性时,我能够在我的开发环境中重现异常:
screenshot of expanded Results property of the _context.Group object
It 's understandable, that when expanding the Results, it loads the instance needed to be updated and that' s抛出异常的原因 . 但是部署的 生产环境 环境是什么?

谢谢您的帮助!

UPDATE1 Group 型号:

public class Group
{
    [Display(Name = "ID")]
    public string Id { get; set; }

    public virtual Country Country { get; set; }

    [Required]
    [Display(Name = "Country")]
    [ForeignKey("Country")]
    public string CountryCode { get; set; }

    [Required]
    [Display(Name = "Name")]
    public string Name { get; set; }
}

UPDATE2 基于@Mithgroth的回答,我能够覆盖函数 _context.Update() ,每次使用时都不需要try-catch:

public interface IEntity 
{
    string Id { get; }
}

public override EntityEntry<TEntity> Update<TEntity>(TEntity entity)
{
    if (entity == null)
    {
        throw new System.ArgumentNullException(nameof(entity));
    }

    try
    {
        return base.Update(entity);
    }
    catch (System.InvalidOperationException)
    {
        var originalEntity = Find(entity.GetType(), ((IEntity)entity).Id);
        Entry(originalEntity).CurrentValues.SetValues(entity);
        return Entry((TEntity)originalEntity);
    }
}

1 回答

  • 5

    请改用以下内容:

    var group = _context.Group.First(g => g.Id == model.Group.Id);
    _context.Entry(group).CurrentValues.SetValues(model.Group); 
    await _context.SaveChangesAsync();
    

    异常可能是由许多不同的场景引起的,但问题是,您正在尝试更改已标记为不同的对象的状态 .

    例如,这会产生相同的异常:

    var group = new Group() { Id = model.Id, ... };
    db.Update(group);
    

    或者你可能已经分离了N层儿童,这一切都是可能的 .

    这可确保您只是覆盖现有实体的值 .

相关问题