オプティミスティック コンカレンシー:概要
LINQ to SQL はオプティミスティック コンカレンシーをサポートします。 LINQ to SQL のドキュメントでオプティミスティック コンカレンシーの説明に使用されている用語を次の表に示します。
用語 | 説明 |
---|---|
コンカレンシー | 2 人以上のユーザーがデータベースの同じ行を同時に更新しようとした状況のことです。 |
コンカレンシーの競合 | 2 人以上のユーザーが、行の中の 1 つまたは複数の列に対し、互いに競合する値を送信しようとした状況のことです。 |
コンカレンシー制御 | コンカレンシーの競合を解決するために使用する手法のことです。 |
オプティミスティック コンカレンシー | 他のトランザクションが行の値に変更を加えていないかどうかをまず調べたうえで変更の送信を許可する手法のことです。 これと対照的なのが "ペシミスティック コンカレンシー制御" で、レコードをロックすることでコンカレンシーの競合を防ぎます。 "オプティミスティック" (楽観的) という名前が付いているのは、トランザクションどうしが競合する可能性は小さいものと見なす方法であるためです。 |
競合の解決 | データベースを再度クエリしてから相違点を調整することによって競合する項目を更新する処理のことです。 オブジェクトを更新するときには、LINQ to SQL の変更トラッカーによって、以下のデータが記録されます。 - データベースからもともと取得され、更新チェックに使用された値。 - その後のクエリで取得された新しいデータベース値。 次に LINQ to SQL は、オブジェクトが競合しているかどうか (つまり 1 つまたは複数のメンバー値が変更されているかどうか) を判断します。 オブジェクトが競合している場合、LINQ to SQL では次に、どのメンバーが競合しているかが判断されます。 LINQ to SQL が見つけたメンバーの競合は、競合の一覧に追加されます。 |
LINQ to SQL のオブジェクト モデルで "オプティミスティック コンカレンシーの競合" が発生するのは、次の 2 つの条件が両方とも成り立つ場合です。
クライアントがデータベースに変更を送信しようとした。
データベースで、そのクライアントによる最後の読み取り以降に、1 つまたは複数の更新チェック値が更新されている。
この競合を解決するためには、オブジェクトのどのメンバーが競合しているかを判別し、どのように対処するかを決定することが必要です。
Note
オプティミスティック コンカレンシーのチェックに関与するのは、Always または WhenChanged として割り当てられているメンバーのみです。 Never と指定されているメンバーには、チェックは実行されません。 詳細については、「UpdateCheck」を参照してください。
例
次のシナリオは、ユーザー 1 が、更新の手始めとして、データベースの行をクエリした状況です。 ユーザー 1 が取得した行には、Alfreds、Maria、および Sales という値が入っています。
ユーザー 1 は、Manager 列の値を Alfred に、また Department 列の値を Marketing に、それぞれ変更しようと考えています。 しかし、ユーザー 1 がその変更を発行する前に、ユーザー 2 がデータベースに変更を送信しました。 その結果、Assistant 列の値は Mary に、また Department 列の値は Service に、それぞれ変更されました。
ここで、ユーザー 1 が変更を送信しようとすると、送信は失敗し、ChangeConflictException 例外がスローされます。 このような結果になるのは、データベースの Assistant 列と Department 列の値が、予期した値と異なるためです。 Assistant 列と Department 列を表すメンバーが競合しています。 この状況をまとめると次の表のようになります。
State | 管理者 | Assistant | Department |
---|---|---|---|
元の状態 | Alfreds | Maria | Sales |
ユーザー 1 | Alfred | Marketing | |
ユーザー 2 | Mary | サービス |
このような競合は、いくつかの方法で解決できます。 詳細については、変更の競合を管理する」を参照してください。
競合の検出と解決のチェック リスト
競合の検出と解決は、さまざまな詳細レベルで行うことができます。 極端な方法としては、すべての競合を 3 つの方法 (RefreshMode を参照) のいずれかで 1 つで解決し、それ以外の考慮を一切加えないという方法もあります。 正反対の方法としては、競合している各メンバーについて、それぞれの競合の種類ごとに、特定の処理を指定するという方法もあります。
オブジェクト モデルの UpdateCheck オプションを指定または変更します。
詳細については、コンカレンシーの競合を検査するメンバーを指定する」を参照してください。
SubmitChanges の呼び出しの try/catch ブロックで、例外がどの時点でスローされるかを指定します。
詳細については、コンカレンシー例外をいつスローするかを指定する」を参照してください。
取得する競合の詳細さを判断し、それに応じたコードを try/catch ブロックに記述します。
詳細については、エンティティの競合情報を取得する」および「方法: メンバーの競合情報を取得する」を参照してください。
try
/catch
コードで、発見されたさまざまな競合を解決する方法を指定します。詳細については、データベース値を維持することで競合を解決する」、「方法: データベース値を上書きすることで競合を解決する」、「方法: データベース値とマージすることで競合を解決する」を参照してください。
競合の発見と解決をサポートする LINQ to SQL の型
LINQ to SQL で、オプティミスティック コンカレンシーの競合の解決をサポートするクラスと機能を以下に示します。