I have a controller which calls the ChangeActivity method, the source and destination is gained using another dbContext than what is used here.
All code can be found here.
I also have a lot of unit tests which also test aginst an SQL Server database, and they do not encounter this problem.
Models
public class EntryModel
{
public int Id { get; set; }
public List<ActivityModel> Activities { get; set; }
...
}
public class ActivityModel
{
public int Id { get; set; }
...
}
Problematic Code
public ActivityChangeModel ChangeActivity(ActivityModel source, ActivityModel destination, Guid userGuid)
{
DeleteActivity(source);
OverrideEntries(source, destination, userGuid);
var change = AddChange(source, destination, userGuid);
_db.SaveChanges();
return change;
}
private void DeleteActivity(ActivityModel source)
{
var model = _db.Activity.Single(x => x.Id == source.Id);
model.Deleted = true;
}
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;
}
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;
}
}
private ActivityChangeModel AddChange(ActivityModel source, ActivityModel destination, Guid userGuid)
{
var change = new ActivityChangeModel(source, destination, _timeService.Current, userGuid);
_db.ActivityChange.Add(change); // Throws Error
return change;
}
The error which is thrown is
System.InvalidOperationException: 'The instance of entity type 'ActivityModel' cannot be tracked because another instance with the key value '{Id: 5}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.'
I have tried
- Using
_db.ChangeTracker.Clear();before I add the activity to activities - Looking at the changes with
_db.ChangeTracker.DebugView.LongViewjust beforevar activities = entry.Activities;which says that the activityId: 5is being tracked, but it is unchanged
Any help is much appreciated
The reason why I get the error is that the
soruceanddestinationobjects thatChangeActivityrecieves is retrived using anotherdbContext. This means that whendestinationis retrived from the currentdbContextwe now have two equvilentdestination, one which is tracked by the newdbContextand another which is not.The fix is then to either override
soruceanddestinationby_db.Activity.SingleOrDefault(x => x.Id == source.Id)or in my case change thedbContextto be scoped instead of a transiant service. Changing it to scoped, means that the twodestinationobjects we had before, are now the same one and tracked by thedbContext. (Here is the changes I made)