EF Core“另一个实例已被跟踪”

Sim*_*nca 7 c# entity-framework entity-framework-core .net-core asp.net-core

我在使用EF Core 2.2.3更新.Net Core 2.2.0中的实体时遇到问题。

保存更改时发生错误。错误详细信息:无法跟踪实体类型'Asset'的实例,因为已经跟踪了具有相同键值的{'Id'}的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用

这是注册数据库上下文的方式:

services.AddDbContext(options =>

options.UseSqlServer(Configuration.GetConnectionString("DbConnection")), ServiceLifetime.Scoped);
Run Code Online (Sandbox Code Playgroud)

Scoped生命周期是默认设置,但我写的更容易理解。

Anomaly对象是这样的:

public IQueryable<Anomaly> GetAll()
    {return _context.Anomalies.Include(a => a.Asset).Include(a => a.Level)
}

public async Task<Anomaly> GetAnomaly(int anomalyId, User user)
{
    var anomaly = await GetAll()
        .FirstOrDefaultAsync(a => a.Id == anomalyId);

    return anomaly;
}
Run Code Online (Sandbox Code Playgroud)

Update()方法如下所示:

using (var transaction = _context.Database.BeginTransaction())
{
    try
    {
        _context.Anomalies.Update(anomaly);
        _context.SaveChanges();

        transaction.Commit();
    }
    catch (Exception ex)
    {
        transaction.Rollback();
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)

它包含此事务之前的一些检查,但在此上下文中没有足够的相关性。

这是我已经跟踪实例的错误所在。我不明白这是如何发生..如果上下文Scoped,然后

...“在每种情况下,将为每个请求创建一个新的服务实例”

如果我在PUT请求上的上下文与GET请求的上下文不同,那么如何跟踪实体?在最基本的层面上如何运作?

使它工作的唯一方法是设置下,从所有条目ChangeTrackerEntityState.Detached。然后它起作用了..但是至少从我目前的知识来看,这没有任何意义。

我发现了这个问题,但没有有效答案,只有关于EF如何进行跟踪的变通办法和假设。


更新 这里是到位桶的链接,其中包含重新创建此问题的示例:EF核心更新示例

我序列化了从上下文中检索的对象。

左侧跟踪时<====>右侧跟踪时不 左侧跟踪时<====>右侧跟踪时不

Joe*_*tte 15

默认情况下,当您检索实体时,它们会被跟踪,并且由于它们被跟踪,您可以只调用 SaveChanges 而不是调用 Update。您还可以使用 .AsNoTracking() 检索实体而不跟踪它们

如果尚未跟踪,则需要调用 Update,因此如果您使用 AsNoTracking,那么您确实需要在 SaveChanges 之前使用 Update

public IQueryable<Anomaly> GetAll()
{    return _context.Anomalies
    .Include(a => a.Asset)
    .Include(a => a.Level);
}

public async Task<Anomaly> GetAnomaly(int anomalyId, User user)
{
    var anomaly = await GetAll()
        .AsNoTracking()
        .FirstOrDefaultAsync(a => a.Id == anomalyId);

    return anomaly;
}
Run Code Online (Sandbox Code Playgroud)

您还可以检查实体是否被跟踪以了解是否调用更新:

using (var transaction = _context.Database.BeginTransaction())
{
    try
    {

        bool tracking = _context.ChangeTracker.Entries<Anomaly>().Any(x => x.Entity.Id == anomaly.Id);
        if (!tracking)
        {
            _context.Anomalies.Update(anomaly);
        }

        _context.SaveChanges();

        transaction.Commit();
    }
    catch (Exception ex)
    {
        transaction.Rollback();
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 7

我知道我参加这次讨论已经非常晚了,但我遇到了同样的问题,我可以毫无问题地创建一个实体,但是当涉及到更新该实体时,它第一次会成功,但此后每次都会失败。所以我尝试了上面所有的建议,但没有成功。我在文档中做了一些挖掘,发现一旦我调用,DbContext.SaveChanges()就有另一种方法可以调用DbContext.ChangeTracker.Clear()。此方法应该清除所有跟踪实体的更改跟踪器,以便您可以继续进行未来的更新。希望这能找到那些对更新实体有同样挫败感的人。

ChangeTracker.Clear() 文档


Hak*_*çer 5

我试图在没有注意到的情况下更新相同的数据。我花了十个小时才意识到这一点。如果您有像我一样的重复值,我建议删除该数据...阅读此答案的人可能已经像我一样尝试了互联网上的所有解决方案,破坏了项目,陷入了同样的错误,并像我一样省略了重复数据. 你并不孤单,我的朋友。

model.GroupBy(gb => gb.ID).Select(s=>s.First()).ToList();//remove duplicates!!!!!
Run Code Online (Sandbox Code Playgroud)