繁体   English   中英

实体类型的实例……无法跟踪,因为已经在跟踪具有相同键的此类型的另一个实例

[英]The instance of entity type … cannot be tracked because another instance of this type with the same key is already being tracked

给定一个使用 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:无法跟踪实体类型“组”的实例,因为已在跟踪具有相同键的此类型的另一个实例。 添加新实体时,对于大多数键类型,如果未设置键(即,如果键属性为其类型分配了默认值),将创建一个唯一的临时键值。 如果您为新实体显式设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突。 附加现有实体时,确保只有一个具有给定键值的实体实例附加到上下文。

显然没有其他实例。 当我在该行上使用断点停止代码并扩展_context.Group对象的 Results 属性时,我能够在我的开发环境中重现异常: _context.Group 对象的展开结果属性的屏幕截图 可以理解,在展开结果时,它会加载需要更新的实例,这就是抛出异常的原因。 但是部署的生产环境呢?

感谢您的帮助!

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);
    }
}

请改用以下内容:

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 层孩子,这都是可能的。

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

谢谢大家的想法。 我在没有异常的情况下在我的上下文中创建了这个被覆盖的函数,恕我直言,这是一种更好的方法。 此外,使用定义的模型检索主键名称。

此外,它是 EntityFramework 3.0 .NET Core

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System.Linq;



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

        var type = entity.GetType();
        var et = this.Model.FindEntityType(type);
        var key = et.FindPrimaryKey();

        var keys = new object[key.Properties.Count];
        var x = 0;
        foreach(var keyName in key.Properties)
        {
            var keyProperty = type.GetProperty(keyName.Name, BindingFlags.Public | BindingFlags.Instance);
            keys[x++] = keyProperty.GetValue(entity);
        }

        var originalEntity = Find(type, keys);
        if (Entry(originalEntity).State == EntityState.Modified)
        {
            return base.Update(entity);
        }

        Entry(originalEntity).CurrentValues.SetValues(entity);
        return Entry((TEntity)originalEntity);
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM