public async Task Handle(StockReserved @event) { var optionsBuilder = new DbContextOptionsBuilder <StockLinesDbContext>(); optionsBuilder.UseSqlServer("Data Source=localhost;Initial Catalog=DBName;Integrated Security=True;"); using (var context = new StockLinesDbContext(optionsBuilder.Options)) { var available = context.StockLines.Single(p => !p.IsReserved); var existingReservation = context.StockLines.SingleOrDefault(p => p.Id == @event.ReservationId); if (existingReservation != null) { existingReservation.Quantity += @event.Amount; } else { var res = new StockLine { Id = Guid.NewGuid(), Quantity = @event.Amount, IsReserved = true, ReservationId = @event.ReservationId, Product = "coke" }; context.StockLines.Add(res); } available.Quantity -= @event.Amount; var saved = false; while (!saved) { try { await context.SaveChangesAsync(); Console.WriteLine("--------------------------------------------------------------------------------------------"); Console.WriteLine(JsonConvert.SerializeObject(available)); Console.WriteLine(JsonConvert.SerializeObject(existingReservation)); Console.WriteLine("-- --"); Console.WriteLine(JsonConvert.SerializeObject(_entity)); Console.WriteLine("--------------------------------------------------------------------------------------------"); saved = true; } catch (DbUpdateConcurrencyException ex) { foreach (var entry in ex.Entries) { if (entry.Entity is StockLine && !((StockLine)entry.Entity).IsReserved) { var proposedValues = entry.CurrentValues; var databaseValues = (StockLine)entry.GetDatabaseValues().ToObject(); ((StockLine)entry.Entity).Quantity = databaseValues.Quantity - @event.Amount; // Refresh original values to bypass next concurrency check entry.OriginalValues.SetValues(databaseValues); } if (entry.Entity is StockLine && ((StockLine)entry.Entity).IsReserved) { var proposedValues = entry.CurrentValues; var databaseValues = (StockLine)entry.GetDatabaseValues().ToObject(); ((StockLine)entry.Entity).Quantity = databaseValues.Quantity + @event.Amount; // Refresh original values to bypass next concurrency check entry.OriginalValues.SetValues(databaseValues); _entity = entry.Entity; } } } } } }
static void Main(string[] args) { var existingReservations = Enumerable.Range(0, 25).Select(x => (Guid?)Guid.NewGuid()).ToList(); var reservationsToCreate = Enumerable.Range(0, 25).Select(x => Guid.NewGuid()).ToList(); var optionsBuilder = new DbContextOptionsBuilder <StockLinesDbContext>(); optionsBuilder.UseSqlServer("Data Source=localhost;Initial Catalog=DBName;Integrated Security=True;"); using (var context = new StockLinesDbContext(optionsBuilder.Options)) { var temp = context.StockLines.FirstOrDefault(p => p.Product == "coke"); new Checkpoint { TablesToInclude = new List <string> { "StockLines", "Reservations" }.ToArray() }.Reset(context.Database.GetDbConnection().ConnectionString).Wait(); var stockLine = new StockLine { Id = Guid.NewGuid(), Product = "coke", Quantity = 300, IsReserved = false, ReservationId = null }; var existingPerson = context.StockLines.SingleOrDefault(p => p.Product == "coke"); if (existingPerson == null) { context.StockLines.Add(stockLine); context.SaveChanges(); } var reservs = existingReservations.Select(x => new StockLine { Id = x.Value, Product = "coke", Quantity = 1, IsReserved = true, ReservationId = x }); context.StockLines.AddRange(reservs); context.SaveChanges(); } var tasks = GenerateTasks(reservationsToCreate, existingReservations); Task.WhenAll(tasks).Wait(); using (var context = new StockLinesDbContext(optionsBuilder.Options)) { var stockLines = context.StockLines.Where(x => existingReservations.Contains(x.ReservationId)).AsNoTracking().ToList(); var availableStockLine = context.StockLines.SingleOrDefault(x => x.IsReserved == false && x.ReservationId == null); var createdReservations = context.StockLines.Where(x => reservationsToCreate.Contains(x.ReservationId.Value)).AsNoTracking().ToList(); if (stockLines.All(x => x.Quantity == 4)) { Console.WriteLine("ALL existing Reservations updated correctly"); } if (createdReservations.Count == 25 && createdReservations.All(x => x.Quantity == 1)) { Console.WriteLine("ALL reservations created correctly"); } if (availableStockLine != null && availableStockLine.Quantity == 200) { Console.WriteLine("Available stockline quantity is consistent. "); } Console.ReadKey(); } }