0

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" />

これは、私のマシンでの代表的な実行の出力です。UpdateExceptions が表示された場所で実際に実行を完了したことはありません。

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
更新例外: 11
更新例外: 12
更新例外: 13
更新例外: 14
UpdateExceptions: 15
更新例外: 16
更新例外: 17
更新例外: 18
更新例外: 19
UpdateExceptions: 20
更新例外: 21
更新例外: 22
更新例外: 23
UpdateExceptions: 24
UpdateExceptions: 25
更新例外: 26
更新例外: 27
更新例外: 28
更新例外: 29
更新例外: 30
更新例外: 31
更新例外: 32
更新例外: 33
UpdateExceptions: 34
更新例外: 35
更新例外: 36
更新例外: 37
更新例外: 38
更新例外: 39
更新例外: 40
更新例外: 41
UpdateExceptions: 42
更新例外: 43
UpdateExceptions: 44
更新例外: 45
更新例外: 46
更新例外: 47
更新例外: 48
更新例外: 49
UpdateExceptions: 50
更新例外: 51
更新例外: 52
更新例外: 53
UpdateExceptions: 54
更新例外: 55
更新例外: 56
更新例外: 57
更新例外: 58
更新例外: 59
更新例外: 60
UpdateExceptions: 61
UpdateExceptions: 62
UpdateExceptions: 63
UpdateExceptions: 64
UpdateExceptions: 65
UpdateExceptions: 66
更新例外: 67
UpdateExceptions: 68
更新例外: 69
更新例外: 70
更新例外: 71
更新例外: 72
更新例外: 73
更新例外: 74
更新例外: 75
更新例外: 76
更新例外: 77
更新例外: 78
更新例外: 79
更新例外: 80
更新例外: 81
UpdateExceptions: 82
UpdateExceptions: 83
UpdateExceptions: 84
更新例外: 85
更新例外: 86
更新例外: 87
UpdateExceptions: 88
UpdateExceptions: 89
更新例外: 90
更新例外: 91
更新例外: 92
更新例外: 93
更新例外: 94
更新例外: 95
更新例外: 96
更新例外: 97
更新例外: 98
更新例外: 99
更新例外: 100

ここで何か基本的なことが欠けていますか?

4

1 に答える 1

-1

(これ) をロックすることは、EFCounter の両方のインスタンスに排他的ではないため、本質的に役に立ちません。静的オブジェクトが必要です。

データベースの同時実行性を処理するには、データベースを使用する必要があります。

于 2012-11-20T18:35:27.593 に答える