オプティミスティック同時実行の概要 (LINQ to SQL)
更新 : November 2007
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 つまたは複数の更新チェック値が更新されている。
この競合を解決するためには、オブジェクトのどのメンバが競合しているかを判別し、どのように対処するかを決定することが必要です。
メモ : |
---|
オプティミスティック同時実行のチェックに関与するのは、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 列を表すメンバが競合しています。この状況をまとめると次の表のようになります。
|
Manager |
Assistant |
Department |
---|---|---|---|
元の状態 |
Alfreds |
Maria |
Sales |
ユーザー 1 |
Alfred |
|
Marketing |
ユーザー 2 |
|
Mary |
Service |
このような競合は、いくつかの方法で解決できます。詳細については、「方法 : 変更の競合を管理する (LINQ to SQL)」を参照してください。
競合の検出と解決のチェック リスト
競合の検出と解決は、さまざまな詳細レベルで行うことができます。極端な方法としては、すべての競合を 3 つの方法 (RefreshMode を参照) のいずれかで 1 つで解決し、それ以外の考慮を一切加えないという方法もあります。正反対の方法としては、競合している各メンバについて、それぞれの競合の種類ごとに、特定の処理を指定するという方法もあります。
オブジェクト モデルの UpdateCheck オプションを指定または変更します。
詳細については、「方法 : 同時実行の競合を検査するメンバを指定する (LINQ to SQL)」を参照してください。
SubmitChanges の呼び出しの try/catch ブロックで、例外がどの時点でスローされるかを指定します。
詳細については、「方法 : 同時実行例外をいつスローするかを指定する (LINQ to SQL)」を参照してください。
取得する競合の詳細さを判断し、それに応じたコードを try/catch ブロックに記述します。
詳細については、「方法 : エンティティの競合情報を取得する (LINQ to SQL)」および「方法 : メンバの競合情報を取得する (LINQ to SQL)」を参照してください。
try/catch コードで、発見されたさまざまな競合を解決する方法を指定します。
詳細については、「方法 : データベース値を維持することで同時実行の競合を解決する (LINQ to SQL)」、「方法 : データベース値を上書きすることで同時実行の競合を解決する (LINQ to SQL)」、および「方法 : データベース値とマージすることで同時実行の競合を解決する (LINQ to SQL)」を参照してください。
競合の発見と解決をサポートする LINQ to SQL の型
LINQ to SQL で、オプティミスティック同時実行の競合の解決をサポートするクラスと機能を以下に示します。