using System; using System.Linq; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; await using var connection = new SqliteConnection("Data Source=:memory:;Foreign Keys=True"); await connection.OpenAsync(); var options = new DbContextOptionsBuilder().UseSqlite(connection).Options; await using (var seed = new LabDb(options)) { await seed.Database.EnsureCreatedAsync(); seed.Items.Add(new Item { Name = "Initial", Version = 1 }); await seed.SaveChangesAsync(); } await using var first = new LabDb(options); await using var second = new LabDb(options); var winner = await first.Items.SingleAsync(); var stale = await second.Items.SingleAsync(); winner.Name = "Winner"; winner.Version++; await first.SaveChangesAsync(); stale.Name = "Stale"; stale.Version++; bool conflict = false; try { await second.SaveChangesAsync(); } catch (DbUpdateConcurrencyException ex) { conflict = ex.Entries.Count == 1; } await using var verify = new LabDb(options); var stored = await verify.Items.AsNoTracking().SingleAsync(); Check(conflict && stored.Name == "Winner" && stored.Version == 2, "original token prevents stale write"); Console.WriteLine("conflict:detected"); Console.WriteLine(stored.Name + ":v" + stored.Version); static void Check(bool condition, string name) { if (!condition) throw new InvalidOperationException("CHECK: " + name); }