实体框架:无法跟踪实体类型“<T>”的实例,因为已跟踪具有键值“{Id: x}”的另一个实例

问题描述 投票:0回答:1

我有一个调用

ChangeActivity
方法的控制器,
source
destination
是使用另一个 dbContext 获得的,而不是这里使用的。 所有代码都可以在这里找到。

我还有很多单元测试,它们也针对 SQL Server 数据库进行测试,但他们没有遇到这个问题。

型号

public class EntryModel
{
   public int Id { get; set; }
   public List<ActivityModel> Activities { get; set; }
   ...
}

public class ActivityModel
{
   public int Id { get; set; }
   ...
}

有问题的代码

public ActivityChangeModel ChangeActivity(ActivityModel source, ActivityModel destination, Guid userGuid)
{
    DeleteActivity(source);
    OverrideEntries(source, destination, userGuid);

    var change = AddChange(source, destination, userGuid);
    return change;
}

private void DeleteActivity(ActivityModel source)
{
    var model = _db.Activity.Single(x => x.Id == source.Id);
    model.Deleted = true;
    _db.SaveChanges();
}

private void OverrideEntries(ActivityModel source, ActivityModel destination, Guid userGuid)
{
    var entries = _db.Entry.Include(x => x.Activities).Where(x => x.Activities.Contains(source)).ToList();
    foreach (var entry in entries)
    {
        entry.Deleted = true;
    }
    _db.SaveChanges();

    foreach (var entry in entries)
    {
        var newEntry = new EntryModel(entry.StartTime, entry.EndTime, entry.RecordedTime, new List<ActivityModel>(), false, userGuid);
        _db.Entry.Add(newEntry);

        var activities = entry.Activities;
        activities.Remove(source);
        activities.Add(destination);
        newEntry.Activities = activities;
        _db.SaveChanges(); // Throws Error
    }
}

抛出的错误是

系统.InvalidOperationException: '无法跟踪实体类型“ActivityModel”的实例,因为已跟踪键值“{Id: 5}”的另一个实例。 附加现有实体时,请确保仅附加一个具有给定键值的实体实例。'

我已经尝试过了

  • 在将活动添加到活动之前使用
    _db.ChangeTracker.Clear();
  • 查看
    _db.ChangeTracker.DebugView.LongView
    之前的
    var activities = entry.Activities;
    的变化,表示正在跟踪活动
    Id: 5
    ,但它没有变化

非常感谢任何帮助

c# .net sql-server entity-framework change-tracking
1个回答
-1
投票

要解决此问题,您可以先分离

ActivityModel
实体,然后再在
OverrideEntries
方法中再次附加它。您可以使用
DbContext.Entry()
方法从上下文中显式分离该实体。这是示例实现:

private void OverrideEntries(ActivityModel source, ActivityModel destination, Guid userGuid)
{
    var entries = _db.Entry.Include(x => x.Activities).Where(x => x.Activities.Contains(source)).ToList();
    foreach (var entry in entries)
    {
        entry.Deleted = true;
    }
    _db.SaveChanges();

    foreach (var entry in entries)
    {
        // Detach the source activity from the context
        _db.Entry(source).State = EntityState.Detached;

        var newEntry = new EntryModel(entry.StartTime, entry.EndTime, entry.RecordedTime, new List<ActivityModel>(), false, userGuid);
        _db.Entry.Add(newEntry);

        var activities = entry.Activities;
        activities.Remove(source);
        activities.Add(destination);
        newEntry.Activities = activities;
    }

    _db.SaveChanges(); // Should not throw an error now
}
© www.soinside.com 2019 - 2024. All rights reserved.