C
C#2y ago
pyrodistic

InvalidOperationException - EF Instance - Identity Resolution

I'm getting:
InvalidOperationException: The instance of entity type 'Vet' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
InvalidOperationException: The instance of entity type 'Vet' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
public async Task<IActionResult> Create(RoomViewModel model)
{
if (ModelState.IsValid)
{
// Converts the model to a Room object.
var room = _converterHelper.ToRoom(model, true);

// Before creating the Room check if there's a room with the same VetId, nulls it if exists.
var previousRoom = _roomRepository.GetByVet((int)model.VetId).AsNoTracking().FirstOrDefault();
if (previousRoom != null)
{
previousRoom.VetId = null;
await _roomRepository.UpdateAsync(previousRoom);
}

// Creates Room
await _roomRepository.CreateAsync(room);

// Changes the room on the related Vet object if provided.
if(room.VetId != null)
{
Vet vet = await _vetRepository.GetByIdAsync((int)room.VetId);

await _vetRepository.UpdateAsync(vet); //Error occurs at this point.
}

return RedirectToAction(nameof(Index));
}
return View(model);
}
public async Task<IActionResult> Create(RoomViewModel model)
{
if (ModelState.IsValid)
{
// Converts the model to a Room object.
var room = _converterHelper.ToRoom(model, true);

// Before creating the Room check if there's a room with the same VetId, nulls it if exists.
var previousRoom = _roomRepository.GetByVet((int)model.VetId).AsNoTracking().FirstOrDefault();
if (previousRoom != null)
{
previousRoom.VetId = null;
await _roomRepository.UpdateAsync(previousRoom);
}

// Creates Room
await _roomRepository.CreateAsync(room);

// Changes the room on the related Vet object if provided.
if(room.VetId != null)
{
Vet vet = await _vetRepository.GetByIdAsync((int)room.VetId);

await _vetRepository.UpdateAsync(vet); //Error occurs at this point.
}

return RedirectToAction(nameof(Index));
}
return View(model);
}
After restarting the application everything seems to be correctly updated despite the error. I've read a couple of stackoverflow posts, but I couldn't figure out what to do in order to fix this. Would appreciate any help.
2 Replies
pyrodistic
pyrodistic2y ago
Changing it to:
public async Task<IActionResult> Create(RoomViewModel model)
{
if (ModelState.IsValid)
{
var room = _converterHelper.ToRoom(model, true);
if(model.VetId != null)
{
var previousRoom = _roomRepository.GetByVet((int)model.VetId).AsNoTracking().FirstOrDefault();
if (previousRoom != null)
{
previousRoom.VetId = null;
await _roomRepository.UpdateAsync(previousRoom);
}
}
await _roomRepository.CreateAsync(room);
return RedirectToAction(nameof(Index));
}
return View(model);
}
public async Task<IActionResult> Create(RoomViewModel model)
{
if (ModelState.IsValid)
{
var room = _converterHelper.ToRoom(model, true);
if(model.VetId != null)
{
var previousRoom = _roomRepository.GetByVet((int)model.VetId).AsNoTracking().FirstOrDefault();
if (previousRoom != null)
{
previousRoom.VetId = null;
await _roomRepository.UpdateAsync(previousRoom);
}
}
await _roomRepository.CreateAsync(room);
return RedirectToAction(nameof(Index));
}
return View(model);
}
Seems to fix the issue and it still appears to fully work, will do some more testing but still appreciate any advice. Thanks in advance!
Cisien
Cisien2y ago
The repository pattern isnt doing you any favors here, ef already implements the repository pattern, making your abstraction unnecessary additional complexity. Ef already handles update detection so you dont need to Asp.net core api controllers ensure the model state is valid, its not a check you need to perform any longer Consider making the converthelper methods extension methods, this lets you write code like model.ToRoom(true);