2

Linq To SQLDataContextにはオーバーロードがあり、オプティミスティック同時実行例外がスローされたときに更新を続行できるようにし、開発者に単一のTryCatchブロックSubmitChangesで後で競合を解決するメカニズムを提供します。

WCFDataServicesContextは、少なくともエラーが発生したときに更新を続行し、競合する更新を未解決のままにして、後で調べることができるようにするメソッドのSaveChangedOptions.ContinueOnErrorパラメーター があります。SaveChanges

(1)では、なぜそのObjectContext.SaveChanges方法にそのようなオプションがないのですか?

(2)Linq To SQLの動作を模倣する更新パターンはありますか?私がMSDNで見つけた例では、複数の更新が行われた場合に、単一のTryCatchブロックでホームが表示されるように見えます。ただし、このパターンでは、競合する各更新を個別に調査することはできません。最初の競合について警告し、「1回のスイープでテーブルをクリーンアップ」して、楽観的同時実行性の例外が発生しないようにするオプションを提供します。存在するかどうか、そしてそれらについて何をしたいのかを知ること。

4

1 に答える 1

5

では、なぜ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でいつでも提案を行うか、コードをチェックして自分で実装してみることができます。この機能は複雑すぎて、簡単に実装できるかもしれません。

于 2012-09-02T20:20:07.383 に答える