I have the most simple ASP.NET Core 3.1 Web API solution, with a model project that uses Entity Framework Core 3.1.7 to map to my models to SQL Server.
I have the following entity:
[Table("SessionDetails")]
public class SessionDetailsModel
{
public long Id { get; set; }
public DateTime CreateDate { get; set; }
public Guid Token { get; set; }
public bool IsValid { get; set; }
}
which is created each time a user calls the Login endpoint (POST).
The db context is configured the following way:
public class RunMeDbContext : DbContext
{
public RunMeDbContext(DbContextOptions<RunMeDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SessionDetailsModel>()
.HasKey(x => new {x.Id, x.CreateDate});
base.OnModelCreating(modelBuilder);
}
public DbSet<SessionDetailsModel> SessionDetails { get; set; }
}
The insertion succeeds fine, but then when I call the logout endpoint which gets the previously created SessionDetails record by the token field, and tries to update the 'IsValid' field (bool) from true to false, I get the following exception:
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
I'm the only one that's connected to the database, and after reading about concurrency conflicts, I can assure no other changes have been made to the record.
My code:
public async Task<bool> InvalidateSession(Guid token)
{
var session = await _dbContext.SessionDetails.FirstOrDefaultAsync(sd => sd.Token.Equals(token))
.ConfigureAwait(false);
if (session == null)
return false;
session.IsValid = false;
_dbContext.Update(session);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
return true;
}
Hint: while debugging I noticed that although the only field I'm changing is 'IsValid = false', for some strange reason, the Token field is modified too (though it's value is the same):
