我有一个调用
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
,但它没有变化非常感谢任何帮助
要解决此问题,您可以先分离
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
}