-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.cs
93 lines (75 loc) · 2.62 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Xunit;
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
[ConcurrencyCheck]
public decimal Price { get; set; }
}
public class ProductContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=MockDatabase;Trusted_Connection=True;");
}
}
public class Program
{
public static void Main(string[] args)
{
}
}
public class CaseReproduction : IDisposable
{
public CaseReproduction()
{
using var context = new ProductContext();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
context.Add(new Product
{
Name = "Coconut",
Description = "A very tasty coconut.",
Price = 10
});
context.SaveChanges();
}
public void Dispose()
{
using var context = new ProductContext();
context.Database.EnsureDeleted();
}
[Fact]
public async Task ApplyDiscountToCoconut_UsingAssignmentSubtractionOperator_ThrowsDbUpdateConcurrencyException()
{
await Assert.ThrowsAsync<DbUpdateConcurrencyException>(() => ApplyDiscountToCoconut(coconut => coconut.Price -= 2));
}
[Fact]
public async Task ApplyDiscountToCoconut_UsingAssignmentOperator_ThrowsRetryLimitExceededException()
{
await Assert.ThrowsAsync<RetryLimitExceededException>(() => ApplyDiscountToCoconut(coconut => coconut.Price = 8));
}
private async Task ApplyDiscountToCoconut(Action<Product> discountAction)
{
using var context = new ProductContext();
var executionStrategy = new SqlServerRetryingExecutionStrategy(
context,
2,
TimeSpan.FromSeconds(10),
new int[] { 17142 }); // Add server paused exception to transient exceptions for emulating transient error.
await executionStrategy.ExecuteAsync(async () =>
{
using var transaction = await context.Database.BeginTransactionAsync();
var coconut = await context.Products.SingleAsync(x => x.Name == "Coconut");
discountAction(coconut);
await context.SaveChangesAsync(true);
await context.Database.ExecuteSqlRawAsync("RAISERROR(17142,16,0) WITH LOG;");
await transaction.CommitAsync();
});
}
}