では、なぜObjectContext.SaveChangesメソッドにそのようなオプションがないのですか?
最も簡単な答えは、Linq-to-Sql、Entity Framework、およびWCF Data Servicesがすべて異なるチームによって実装されており、これらのチーム間の内部通信が期待どおりに機能しないためだと思います。以前の回答の1つで、新しいAPIに欠けているいくつかの興味深い機能について説明しましたが、これが欠けている機能ではないと思います。これについては、回答の2番目の部分で説明します。
WCF Data Servicesには、EntityFrameworkの一部である必要があるより興味深い機能があります。例えば:
Linq To SQLの動作を模倣する更新パターンはありますか?
これを解決する方法にはパターンがありますが、おそらく気に入らないでしょう。EFSaveChanges
は作業単位として機能します。すべての変更を保存するか、まったく保存しません。SaveChanges
変更の一部のみが永続化され、単一の呼び出しで処理されるべきではない場合に、保存操作が発生する可能性があるシナリオがある場合。変更の各アトミックセットには、独自のSaveChanges
呼び出しが必要です。
using (var scope = new TransactionScope(...)) {
foreach (var entity in someEntitiesToModify) {
try {
context.SomeEntities.Attach(entity);
context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
context.SaveChanges();
catch (OptimisticConcurrencyException e) {
// Do something here
context.Refresh(e.StateEntries[0].Entity, RefreshMode.ClientWins);
context.SaveChanges();
}
}
scope.Complete();
}
この機能が存在しない理由は、一般的ではなく、前述のように作業単位のパターンに反するためだと思います。この例を考えてみましょう。
- エンティティをロードします
- ロードしたエンティティのナビゲーションプロパティに新しい依存エンティティを追加します
- ロードされたエンティティで何かを変更します
- その間に、他の誰かがロードされたエンティティを同時に削除します
- 緩和された競合解決でSaveChangesをトリガーします
- EFはプリンシパルエンティティへの変更を保存しようとしますが、データベースに更新するエンティティがないため、競合します
- 紛争解決が緩和されているため、EFは継続します
- EFは依存エンティティを挿入しようとしますが
SqlException
、プリンシパルエンティティがデータベースに存在しないために起動します。この例外は永続化操作を中断し、プリンシパルエンティティがあるため、参照整合性について不平を言っている理由がわかりません。(コンテキストの内部状態の不整合のために、この挿入が発生せず、EFが別の例外を発生させる可能性もありますが、EFの内部実装に依存します)。
これにより、競合解決の全体的な緩和がはるかに複雑な機能になります。それを解決するための私見の3つの方法があります:
- 単にそれをサポートしていません。エンティティごとの競合解決が必要な場合でも、上記の例を使用できますが、複雑なシナリオでは解決が難しいため、機能しない場合があります。
- 競合が発生するたびにデータベース変更セットを再構築します。これは、残りの変更セットを調査し、競合するエンティティに関連するすべてのエンティティとそれらの関係などを処理された永続性から除外することを意味します。問題があります:EFは変更されたエンティティを処理から除外できません。それは仕事の単位の意味を壊すでしょう、そして私はそれをもう一度繰り返します:紛争解決を緩和することは仕事の単位の意味を壊すこともできます。
- プリンシパルエンティティが競合している場合でも、EFに依存関係を続行させます。これには、データベース例外を処理し、その内容を理解して、プリンシパルの競合またはその他のエラー(永続化操作全体がすぐに失敗するはずです)が原因で例外が発生したかどうかを知る必要があります。コードレベルでデータベースの例外を理解するのは非常に難しい場合があり、さらに、サポートされているすべてのデータベースに固有のプロバイダーです。
そのような機能を作成できない可能性があるという意味ではありませんが、関係に関してはすべてのシナリオをカバーする必要があり、これはかなり複雑になる可能性があります。Linq-to-Sqlがこれを処理するかどうかはわかりません。
Data UserVoiceでいつでも提案を行うか、コードをチェックして自分で実装してみることができます。この機能は複雑すぎて、簡単に実装できるかもしれません。