web-dev-qa-db-ja.com

AsNoTracking()でエンティティを取得すると、DetectChanges()の自動呼び出しが無効になりますか?

このAsNoTracking()DetectChanges()、およびAutoDetectChangesEnabledの概念を知ったのはごく最近のことです。 AsNoTracking()を使用してEntity Framework経由でデータベースからレコードをフェッチすると、Entity Frameworkはそれらのレコードの変更を追跡せず、その場合、フェッチされたレコードのプロパティの更新は失敗します。

私の質問は、レコードがその方法でフェッチされる場合、DetectChanges()への自動呼び出しを無効にするか、または次のように設定して明示的に行う必要があるかどうかです。

Context.Configuration.AutoDetectChangesEnabled = false;

また、読み取り専用の目的で厳密にデータをフェッチしているときに両方のアクションが実行されると、パフォーマンスの面でどのような影響があるかを教えてください。

Context.Configuration.AutoDetectChangesEnabled = false;
Context.Set<T>().AsNoTracking();
25
Sayan Pal

また、DetectChanges()への自動呼び出しを無効にします

いいえ、ありません。ただし、AsNoTrackingDetectChangesは互いに関係がないことを理解する必要があります(EFの一部であることを除きます)。 AsNoTrackingでフェッチされたオブジェクトは、AutoDetectChangesが有効かどうかにかかわらず、決して変更検出されません。さらに、AsNoTrackingDbSetレベルで機能し、AutoDetectChangesEnabledはコンテキストレベルで機能します。 DbSetメソッドがコンテキスト全体に影響するのは悪いことです。

または、[設定AutoDetectChangesEnabled]を明示的に行う必要がある

まあ、AutoDetectChangesを無効にすべきではないでしょう。 もしあなたはそれをするあなたはあなたが何をしているのかを知らなければなりません。

両方のアクションが実行された場合、(パフォーマンスに関して)どのような影響がありますか

言ったように、それらは関連していません。どちらも独自の方法でパフォーマンスを向上させることができます。

  • AsNoTrackingは、読み取り専用データを取得したい場合に最適です。副作用はありません(例:その効果は明ら​​かです)
  • 設定AutoDetectChangesEnabled = falseDetectChanges(多数になる可能性があります)の自動呼び出しを停止しますが、注意が必要な副作用があります。 Lerman&Millerの本からDbContext

    DetectChangesを呼び出す必要がある場合の作業は、表示されるほど簡単ではありません。 Entity Frameworkチームは、パフォーマンスの問題が発生している場合にのみ、手動でDetectChangesを呼び出すように切り替えることを強くお勧めします。また、コードのパフォーマンスが低いセクションに対してのみ自動DetectChangesをオプトアウトし、問題のセクションの実行が終了したら再度有効にすることをお勧めします。

31
Gert Arnold

_AutoDetectChangesEnabled = false_を設定すると、パフォーマンスに大きな影響(つまり、10倍)が生じる可能性があることがわかりました。

背景:私たちのシステムは、変更検出プロキシを使用するEFモデルオブジェクトで完全に構成されています。つまり、すべてのDBフィールドとリレーショナルプロパティが仮想として宣言されています。また、比較的深く構造化されたオブジェクトモデルもあります。つまり、オブジェクトAにはオブジェクトBのセットが含まれ、オブジェクトBにはオブジェクトCのセットなどが含まれます。EF/ LINQクエリを介して重要でない(> 100)数のこれらのオブジェクトをインスタンス化するとコストがかかることがわかりました。たとえば、1つのケースでは、250のオブジェクトをインスタンス化するには約2秒かかりました。同じ構造をインスタンス化することも観察しましたが、代わりに匿名オブジェクトを使用すると約25ミリ秒必要でした。最後に、_AutoDetectChangesEnabled = false_を設定すると、EFモデルオブジェクトをインスタンス化するクエリを使用できるようになり、マテリアライズは約25 msでした。

したがって、少なくとも私たちにとっては、falseに設定することで大きな利益が得られました。作業単位パターンを使用し、作業単位が読み取り専用かどうかを明示的に示します。読み取り専用の作業単位の場合、_AutoDetectChangesEnabled = false_の設定はまったく変更されないため、完全に安全です。実際、私たちは最初のリリースから2年後にこの変更をシステムに追加しました(そのため、コードには既存の作業単位が多数ありました)。この変更によって何も破壊されず、パフォーマンスが大幅に向上しました。

また、AsNoTracking()を試したところ、基本的にパフォーマンスがまったく向上しないことがわかりました。私が理解しているように、AsNoTracking()を使用したクエリは、オブジェクトがIDマップに配置されないことを意味します。これにより、EFがオブジェクトをディスク内で複数回参照した場合、ディスクからオブジェクトを再フェッチします。コンテキスト(たとえば、異なるクエリ内)。したがって、AsNoTracking()には潜在的なマイナス面があります。

実装の詳細

  • 作業単位に多くのインフラストラクチャを提供するDBContextのサブクラスがあります。
  • 私たちの作業単位は、基本的にはコンテキストの軽量ラッパーです
  • 作業ユニットが割り当てられると(通常usingブロックで)、インジェクションを介してこれらのコンテキストの1つを受け取ります(Castle/Windsorを使用します)。
  • 初期化中に、作業ユニットは、AutoDetectChangesEnabledをfalseに設定するコンテキストのメソッドを呼び出します
  • 現在、これをall実行します。これは、変更検出プロキシを常に使用し、AutoDetectChangesEnabledを必要としないためです。
  • 以前は、「読み取り専用」の作業単位に対してのみ行っていました。UoWで何も変更されない場合、変更を検出する必要がないためです(作業単位を割り当てたときに、読み取り専用かどうかを明示的に示します)。
  • -
20
Terry Coatta