I try to implement Microsoft's case for an API Update which is shown below.
First I get the record from the database to determine if it is null. If not, an update will be triggered.
In by code efCore
throws an DBConcurrencyException
because the element has already been tracked.
What's the problem?
// PUT api/contactsconvention/{guid}
[HttpPut("{id}")]
[ApiConventionMethod(typeof(DefaultApiConventions),
nameof(DefaultApiConventions.Put))]
public IActionResult Update(string id, Contact contact)
{
// First tracking in my code
var contactToUpdate = _contacts.Get(id);
if (contactToUpdate == null)
{
return NotFound();
}
// Second tracking in my code -> Exception at dbContext.SaveChanges()
_contacts.Update(contact);
return NoContent();
}
Behind the .Get Method must be a non-chagen-tracking method. So I added it and now it works.
// PUT api/contactsconvention/{guid}
[HttpPut("{id}")]
[ApiConventionMethod(typeof(DefaultApiConventions),
nameof(DefaultApiConventions.Put))]
public IActionResult Update(string id, Contact contact)
{
// First tracking in my code
var contactToUpdate = _contacts.GetAsNoTracking(id);
if (contactToUpdate == null)
{
return NotFound();
}
// Second tracking in my code -> Exception at dbContext.SaveChanges()
_contacts.Update(contact);
return NoContent();
}
// Non-tracking repository method:
return context.Contacts.AsNoTracking().Single(s => s.Id == id);
Also I had a problem with my UnitTests which use a mocked dbSet. The AddRange method also adds ChangeTracking values. These can be removed with the following code as described in this post.
foreach (var entity in InMemoryScheduleDbContext.ChangeTracker.Entries())
{
entity.State = EntityState.Detached;
}