我正在尝试使用EF5 Code First实现一致的多读写器计数器,我遇到并发异常(我预期),但我也遇到了主键约束违规,我没有期望。如果代码创建,则会发生此 ;如果它已经存在,则按预期进行计数。
以下是我正在使用的代码(也包含调试代码):
public class EFCounter
{
private static int UpdateExceptionCount = 0;
private const int StartValue = 1000001;
public int CreateOrIncrement(Guid counterId)
{
using (var context = new EFCounterContext("MsSqlViewModel"))
{
if (context.Counters.Any(cntr => cntr.CounterId == counterId) == false)
{
try
{
context.Counters.Add(
new Counter
{
CounterId = counterId,
Value = StartValue
}
);
context.SaveChanges();
return StartValue;
}
catch (Exception e)
{
//fall through
}
}
var objectContext = ((IObjectContextAdapter) context).ObjectContext;
var counter = context.Counters.First(cntr => cntr.CounterId == counterId);
do
{
try
{
lock (this)
{
counter.Value += 1;
objectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);
return counter.Value;
}
}
catch (OptimisticConcurrencyException ex)
{
objectContext.Refresh(RefreshMode.StoreWins, counter);
}
catch (UpdateException ex)
{
var ueCount = Interlocked.Increment(ref UpdateExceptionCount);
objectContext.Detach(counter);
counter = context.Counters.First(cntr => cntr.CounterId == counterId);
Console.WriteLine("UpdateExceptions: {0}", ueCount);
}
} while (true);
}
}
}
public class Counter
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid CounterId { get; set; }
[ConcurrencyCheck]
public int Value { get; set; }
}
我只是使用Parallel.For
来调用它:
EFCounter counter1 = new EFCounter();
EFCounter counter2 = new EFCounter();
Guid counterId = Guid.NewGuid();
Parallel.For(
1,
10,
i =>
{
Console.WriteLine("1: {0}", counter1.CreateOrIncrement(counterId));
Console.WriteLine("2: {0}", counter2.CreateOrIncrement(counterId));
}
);
供参考,连接字符串:
<add name="MsSqlViewModel" providerName="System.Data.SqlClient" connectionString="Data Source=localhost;Initial Catalog=ESRaffleViewModels;Integrated Security=SSPI" />
以下是我机器上代表性运行的输出;我从未真正完成过RunExceptions出现的运行:
1: 1000001 2: 1000002 UpdateExceptions: 1 1: 1000003 UpdateExceptions: 2 2: 1000004 UpdateExceptions: 3 1: 1000005 UpdateExceptions: 4 2: 1000006 UpdateExceptions: 5 UpdateExceptions: 6 UpdateExceptions: 7 UpdateExceptions: 8 UpdateExceptions: 9 UpdateExceptions: 10 UpdateExceptions: 11 UpdateExceptions: 12 UpdateExceptions: 13 UpdateExceptions: 14 UpdateExceptions: 15 UpdateExceptions: 16 UpdateExceptions: 17 UpdateExceptions: 18 UpdateExceptions: 19 UpdateExceptions: 20 UpdateExceptions: 21 UpdateExceptions: 22 UpdateExceptions: 23 UpdateExceptions: 24 UpdateExceptions: 25 UpdateExceptions: 26 UpdateExceptions: 27 UpdateExceptions: 28 UpdateExceptions: 29 UpdateExceptions: 30 UpdateExceptions: 31 UpdateExceptions: 32 UpdateExceptions: 33 UpdateExceptions: 34 UpdateExceptions: 35 UpdateExceptions: 36 UpdateExceptions: 37 UpdateExceptions: 38 UpdateExceptions: 39 UpdateExceptions: 40 UpdateExceptions: 41 UpdateExceptions: 42 UpdateExceptions: 43 UpdateExceptions: 44 UpdateExceptions: 45 UpdateExceptions: 46 UpdateExceptions: 47 UpdateExceptions: 48 UpdateExceptions: 49 UpdateExceptions: 50 UpdateExceptions: 51 UpdateExceptions: 52 UpdateExceptions: 53 UpdateExceptions: 54 UpdateExceptions: 55 UpdateExceptions: 56 UpdateExceptions: 57 UpdateExceptions: 58 UpdateExceptions: 59 UpdateExceptions: 60 UpdateExceptions: 61 UpdateExceptions: 62 UpdateExceptions: 63 UpdateExceptions: 64 UpdateExceptions: 65 UpdateExceptions: 66 UpdateExceptions: 67 UpdateExceptions: 68 UpdateExceptions: 69 UpdateExceptions: 70 UpdateExceptions: 71 UpdateExceptions: 72 UpdateExceptions: 73 UpdateExceptions: 74 UpdateExceptions: 75 UpdateExceptions: 76 UpdateExceptions: 77 UpdateExceptions: 78 UpdateExceptions: 79 UpdateExceptions: 80 UpdateExceptions: 81 UpdateExceptions: 82 UpdateExceptions: 83 UpdateExceptions: 84 UpdateExceptions: 85 UpdateExceptions: 86 UpdateExceptions: 87 UpdateExceptions: 88 UpdateExceptions: 89 UpdateExceptions: 90 UpdateExceptions: 91 UpdateExceptions: 92 UpdateExceptions: 93 UpdateExceptions: 94 UpdateExceptions: 95 UpdateExceptions: 96 UpdateExceptions: 97 UpdateExceptions: 98 UpdateExceptions: 99 UpdateExceptions: 100
我错过了一些基本的东西吗?
答案 0 :(得分:-1)
锁定(this)并不是EFCounter的两个实例所独有的,因此基本上没用。你需要一个静态对象。
您需要使用数据库来处理数据库并发。