I am getting a DbUpdateConcurrencyException
. It seems to work sometimes as I change code, but fails most of the time, and I have not been able to find a pattern as I change test code.
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException : The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See https://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
When I have to a SQL Server database, and no other programs accessing the same, and no async in node.
The self contained NUnit function is:
-
Delete existing records with the given name by
- Fetch the records using DbSet.Where with the given name
- Execute DbSet.RemoveRange
- Execute DbContext.SaveChanges
-
Create a Database record
- Execute DbSet.Add
- Execute DbContext.SaveChanges
-
Refresh the record
- Fetch the records using DbSet.Where with the primary keys
(This fetches same record as written, but in a separate C# variable) - Make the modifications on the C# structure
- Execute DbContext.SaveChanges
- Fetch the records using DbSet.Where with the primary keys
The C# function (simple one)
DbUserView initialView = new DbUserView {
userName = 'test', fromUrl = 'http://localhost:5000',
eventType = 'quiz', sectionId = 'firstSection', pageId = 'firstPage',
startTime = DateTime.Now, lastActiveTime = DateTime.Now };
[Test]
public void Expt2()
{
string? userName = initialView.userName;
var dbUserViews = exptContext.userViews.Where(
dbUserView => dbUserView.userName == userName);
if (dbUserViews.Count() > 0)
{
exptContext.userViews.RemoveRange(dbUserViews);
exptContext.SaveChanges();
}
Thread.Sleep(2000);
exptContext.userViews.Add(initialView);
exptContext.SaveChanges();
Thread.Sleep(2000);
DbUserView? _refreshView = exptContext.userViews.Find(
initialView.userName, initialView.fromUrl, initialView.startTime);
if (_refreshView == null)
Assert.Fail("Db fetch gave null view");
else
{
DbUserView refreshView = (DbUserView)_refreshView;
refreshView.lastActiveTime = DateTime.Now.ToUniversalTime();
exptContext.userViews.Update(refreshView);
exptContext.ChangeTracker.DetectChanges();
var change = exptContext.ChangeTracker.DebugView.LongView;
exptContext.SaveChanges();
}
}
The database record (nothing fancy)
[Table("user_views")]
[PrimaryKey(nameof(userName), nameof(fromUrl), nameof(startTime))]
public class DbUserView
{
[Column("user_name")]
public string userName { get; set; }
[Column("from_url")]
public string fromUrl { get; set;}
[Column("event_type")]
public string eventType { get; set;}
[Column("frame_id")]
public string frameId { get; set;}
[Column("sub_frame_id")]
public string subFrameId { get; set;}
[Column("start_time")]
public DateTime startTime { get; set; }
[Column("last_active_time")]
public DateTime lastActiveTime { get; set; }
}
And the context is (nothing fancy)
public class ExptContext : DbContext
{
public DbSet<DbUserView> userViews { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
string? connStr = Environment.GetEnvironmentVariable("SQLCONNSTR_DbConn");
optionsBuilder.UseSqlServer(connStr);
}
public static ExptContext dbContext = new ExptContext();
}
I also tried to print the changes using code below, but debug log was straightforward (since I have only one record)
private void showChanges()
{
exptContext.ChangeTracker.DetectChanges();
var changes = exptContext.ChangeTracker.DebugView.LongView.ToString();
Console.WriteLine(changes);
}
Parts of the code work sometimes, and it is pretty random.
Specific questions (in addition to your thoughts)
- Is there something basic I am missing?
- Is there a way to debug log
DbContext.SaveChanges
? - How does
SaveChanges
run? Can network timeouts cause this error? - Is there any way to turn off optimistic concurrency control, while relying on the other features of Entity Framework Core?
2