変更の保存と同時実行制御の管理 (Entity Framework)

エンティティ フレームワーク は、オプティミスティック同時実行制御モデルを実装しています。このことは、データ ソースのデータに対してロックが保持されないことを意味します。しかし、既定では、Object Services では、同時実行制御がチェックされることなく、オブジェクトの変更がデータベースに保存されます。高いレベルの同時実行制御が行われるプロパティに対しては、次の例に示すように、ConcurrencyMode="fixed" の属性でエンティティ プロパティを概念レイヤで定義することをお勧めします。

<Property Name="Status" Type="Byte" Nullable="false" ConcurrencyMode="Fixed" />

この属性を使用すると、Object Services では、変更がデータベースに保存される前に、データベース内の変更がチェックされます。競合する変更がある場合は、OptimisticConcurrencyException が発生します。詳細については、「オブジェクト コンテキストでデータの同時実行制御を管理する方法 (Entity Framework)」を参照してください。ストアド プロシージャを使用してデータ ソースへの更新を行う エンティティ データ モデル を定義しても、OptimisticConcurrencyException が発生する可能性があります。この場合、更新を実行するときに使用するストアド プロシージャによって、行が更新されなかったことが報告されると例外が発生します。詳細については、「ストアド プロシージャのサポート (Entity Framework)」を参照してください。

高いレベルの同時実行制御シナリオで更新を行う場合は、Refresh を頻繁に呼び出すことをお勧めします。Refresh を呼び出すと、変更が反映される方法が RefreshMode によって制御されます。StoreWins オプションを使用すると、Object Services によってオブジェクト キャッシュ内のすべてのデータがデータベースの対応する値で上書きされます。これに対し、ClientWins オプションを使用すると、キャッシュ内の元の値がデータ ソースの最新の値で置換されます。そのため、キャッシュ内のデータに対して行われた変更とデータ ソース内の同じデータに対して行われた変更の間の競合が排除され、オブジェクト キャッシュ内のすべての変更済みデータがデータ ソースに安全に保存されます。

データソースへの更新によってオブジェクト コンテキスト内の他のオブジェクトに属するデータが変更される場合は、SaveChanges メソッドを呼び出してから Refresh メソッドを呼び出します。たとえば AdventureWorks Sales モデルで新しい SalesOrderDetail が追加されると、トリガによって SubTotal 列が更新されて新しい項目がある集計に反映されます。この場合、Refresh メソッドを呼び出して、その注文の SalesOrderHeader オブジェクトを渡します。これにより、トリガで生成された値がオブジェクト コンテキストの SalesOrderHeader オブジェクトに送信されます。

Object Services は、キャッシュ内のオブジェクトに対して行われた変更を追跡します。SaveChanges メソッドを呼び出すと、Object Services では、変更をデータ ソースにマージする処理が試行されます。オブジェクトがキャッシュに追加された後またはキャッシュ内で更新された後、オブジェクト キャッシュのデータ変更がデータ ソース内の変更と競合する場合、OptimisticConcurrencyException が発生して SaveChanges が失敗します。その結果、トランザクション全体がロールバックされます。OptimisticConcurrencyException が発生した場合、次の例に示すように、Refresh を呼び出して、競合を解決するためにオブジェクト データ内のデータを維持するか (ClientWins)、オブジェクト キャッシュ内のデータをデータ ソースのデータで更新するか (StoreWins) を指定する必要があります。

Try
    ' Try to save changes, which may cause a conflict.
    Dim num As Integer = context.SaveChanges()
    Console.WriteLine("No conflicts. " + _
                      num.ToString() + " updates saved.")
Catch ex As OptimisticConcurrencyException
    ' Resolve the concurrency conflict by refreshing the 
    ' object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders)

    ' Save changes.
    context.SaveChanges()
    Console.WriteLine("OptimisticConcurrencyException " _
                      + "handled and changes saved.")
End Try
try
{
    // Try to save changes, which may cause a conflict.
    int num = context.SaveChanges();
    Console.WriteLine("No conflicts. " +
        num.ToString() + " updates saved.");
}
catch (OptimisticConcurrencyException)
{
    // Resolve the concurrency conflict by refreshing the 
    // object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders);

    // Save changes.
    context.SaveChanges();
    Console.WriteLine("OptimisticConcurrencyException "
    + "handled and changes saved");
}

ObjectContext に追加されたオブジェクトがデータ ソースで正常にデータを作成できない場合、SaveChanges によって UpdateException が生成されます。これは、リレーションシップで指定される外部キーを持つ行が既に存在していると発生します。これが発生すると、Refresh を使用してオブジェクト コンテキストで追加済みのオブジェクトを更新できなくなります。代わりに、MergeOptionOverwriteChanges の値でオブジェクトを再度読み込みます。

オブジェクト コンテキストの管理の詳細については、「オブジェクト コンテキストでデータの同時実行制御を管理する方法 (Entity Framework)」を参照してください。

Object Services では、System.Transactions 名前空間を使用して定義されたトランザクションも容認されます。詳細については、「Object Services のトランザクションの管理 (Entity Framework)」を参照してください。

参照

概念

オブジェクトの追加、変更、および削除 (Entity Framework)

その他のリソース

オブジェクトの使用 (Entity Framework)