C
C#2d ago
Rename

EF Core 8: System.InvalidOperationException: 'The instance of entity type cannot be tracked..

Hi guys, I'm getting this error
System.InvalidOperationException: 'The instance of entity type 'OccurrenceRule' cannot be tracked because another instance with the key value '{Id: 0b87b74b-c1b9-48f5-954a-2613fbab92d0}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.'
System.InvalidOperationException: 'The instance of entity type 'OccurrenceRule' cannot be tracked because another instance with the key value '{Id: 0b87b74b-c1b9-48f5-954a-2613fbab92d0}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.'
but the thing is for the query where OccurrenceRule is loaded, I'm using AsNoTracking() method since there won't be any changes for that entity anyways. the first method loads a list of StaffMembers along with the neccessary navigation properties, where this is also included:
//load StaffMember OccurrenceItem
var occurrenceItems = await dbContext.OccurrenceItems
.Where(oi => EF.Constant(staffMemberIds).Contains(oi.StaffMemberId))
.Include(oi => oi.Type)
.Include(oi => oi.Rule)
.AsNoTracking()
.ToListAsync();
//load StaffMember OccurrenceItem
var occurrenceItems = await dbContext.OccurrenceItems
.Where(oi => EF.Constant(staffMemberIds).Contains(oi.StaffMemberId))
.Include(oi => oi.Type)
.Include(oi => oi.Rule)
.AsNoTracking()
.ToListAsync();
and I can see that right after that method, if I call dbContext.ChangeTracker.Entries() it throws this error initially in quickwatch, and if I evaluate it again, it shows the list of entries. if I continue the code execution after it shows the list of entries. I do NOT run into this error at all and the full operation/endpoint completes successfully. I was under the impression that if I use .AsNoTracking when loading the data, those entries should not be added to the DbContext.ChangeTracker at all I get the error when I call dbContext.SaveChanges(); any ideas?
6 Replies
Angius
Angius2d ago
Usually when I see an issue with an entity being already tracked, it's when there's some async/await tomfuckery going on Like .Result being used instead of await, an async void method somewhere, a task not being awaited at all, this sorta thing
Rename
RenameOP2d ago
well as far as I can tell I am awaiting properly, from my endpoint I call a commandHandler service which begins like so:
protected override async Task<OutputPostUpdateWorkWeekShift> OnExecute(InputPostUpdateWorkWeekShift input)
{
//Here, dbContext has no entries

var staffMember = (await staffMemberRepository.GetForWorkWeek(input.StaffMemberId)).FirstOrDefault()
?? throw new SmartRotaException(StatusCodes.Status404NotFound, "There was no staff member found with the provided ID.");

//Here dbContext has a lot of uneccessary entries.
...rest of the code
protected override async Task<OutputPostUpdateWorkWeekShift> OnExecute(InputPostUpdateWorkWeekShift input)
{
//Here, dbContext has no entries

var staffMember = (await staffMemberRepository.GetForWorkWeek(input.StaffMemberId)).FirstOrDefault()
?? throw new SmartRotaException(StatusCodes.Status404NotFound, "There was no staff member found with the provided ID.");

//Here dbContext has a lot of uneccessary entries.
...rest of the code
and the GetForWorkWeek method is in the text file (sorry it's a bit long but simple)
Ꜳåąɐȁặⱥᴀᴬ
it could be that you are assigning same object in navigation properties multiple times and than saving it
Rename
RenameOP11h ago
yeah actually I was assigning navigation properties as I've got rich domain entities filled with a lot of logic. I was able to fix it by changing my update method to this:
public TEntity Update(TEntity entity)
{
dbContext.Entry(entity).State = EntityState.Modified; //this will only update the entity and not it's navigation properties
//var entry = dbContext.Set<TEntity>().Update(entity);
dbContext.SaveChanges();
return entity;
}
public TEntity Update(TEntity entity)
{
dbContext.Entry(entity).State = EntityState.Modified; //this will only update the entity and not it's navigation properties
//var entry = dbContext.Set<TEntity>().Update(entity);
dbContext.SaveChanges();
return entity;
}
otherwise I'm guessing it was mistakenly tracking navigation properties and thinking those got modified also. I guess this gives me more control over what I want changed so I'll likely be keeping it this way. if anyone happens to have a better idea I'd love to hear it 😅
Ꜳåąɐȁặⱥᴀᴬ
better idea would be using an actual model (probably) why are you loading so much data why are you saving something so complex
Rename
RenameOP10h ago
what I'm saving actually is very simple, at that point just an update of a table's column. but I need to load all that data because we need to do quite some checks before the save. the website was initially in .NET 4.6.2, a legacy app and I've been moving it .NET 8 and refactoring along the way

Did you find this page helpful?