web-dev-qa-db-ja.com

エンティティフレームワーク4.1およびMVC3で動的プロキシを有効または無効にする必要がありますか?

誰かがこの決定を下すのに役立つアドバイスを提供したり、ブログ/記事を指摘したりできますか?プロキシは私にとって非常に異質なようであり、使用することにheしています。私はモデルで仮想プロパティを使用して遅延読み込みを制御する機能が好きですが、それは私が見ることができるほとんどすべての利点です。私のアプリケーションは単純なMVC Webアプリケーションであり、エンティティの状態が変化した場合にフックをコンテキストに接続する必要はありません。

とにかく、ここに私の長所と短所の非常に限られたリストがあります、これのいずれかでベースを離れているかどうかを教えてください。

長所

  • 「保存」または「更新」では、「変更を適用」でシームレスに表示されます
  • 遅延読み込み構成は非常に簡単です。

短所

  • これまでにエンティティにプロキシを使用したことはありません。これは、自分自身や仲間のチームメンバーにとって不快なアプローチの変化です。
  • デバッグしにくい。
  • シリアライズ/デシリアライズが必要な場合は追加のコードが必要です
  • 「保存」または「更新」では、プロキシはコンテキストから取得されたものと同じオブジェクトでなければなりません。
68
matt_dev

EFで動的プロキシについて説明する場合、区別する2つの異なるタイプがあります。

  • 遅延読み込みのプロキシ
  • 変更追跡のプロキシ

通常、変更追跡プロキシは、遅延読み込みのプロキシとしても機能します。その逆は当てはまりません。これは、変更追跡プロキシの要件が高く、特にallプロパティ-スカラープロパティもvirtualでなければならないためです。遅延読み込みの場合、ナビゲーションプロパティはvirtualで十分です。

変更追跡プロキシが常に遅延読み込みを利用できることも、DbContextにこの構成フラグがある主な理由です。

DbContext.Configuration.LazyLoadingEnabled

このフラグはデフォルトでtrueです。 falseに設定すると、プロキシが作成されていても遅延読み込みが無効になります。これは、変更追跡プロキシを使用しているが、遅延読み込みにもそれらのプロキシを使用したくない場合に特に重要です。

オプション ...

DbContext.Configuration.ProxyCreationEnabled

...プロキシ作成を完全に無効にします-変更追跡と遅延読み込みも同様です。

両方のフラグは、エンティティクラスが変更追跡または遅延読み込みプロキシを作成するための要件を満たしている場合にのみ意味を持ちます。

これで、動的遅延読み込みプロキシの目的がわかりました。それでは、なぜ動的な変更追跡プロキシを使用する必要があるのでしょうか?

実際、私が知っている唯一の理由はperformanceです。しかし、これは非常に強力な理由です。スナップショットベースの変更追跡とプロキシベースの変更追跡を比較すると、パフォーマンスの差は非常に大きくなります-私の測定では、50から100の係数が現実的です(スナップショットベースの変更追跡と30から60秒で10000エンティティに約1時間を要した方法から取得)変更追跡プロキシを有効にするためにすべてのプロパティを仮想化した後)。これは、多くの(1000を超える)エンティティを処理および変更するアプリケーションがある場合に重要な要素になります。 Webリクエスト内の単一のエンティティに対してのみCreate/Change/Delete操作がある可能性のあるWebアプリケーションでは、この違いはそれほど重要ではありません。

ほとんどすべての状況で、遅延読み込みプロキシを使用したくない場合は、熱心な読み込みまたは明示的な読み込みを活用して同じ目標を達成できます。プロキシベースの遅延読み込みまたは非プロキシベースの明示的な読み込みのパフォーマンスは同じです。ナビゲーションプロパティが読み込まれると基本的に同じクエリが発生するためです。最初のケースではプロキシがクエリを実行し、2番目のケースでは手書きコードを実行します。そのため、遅延を大きくすることなく、遅延読み込みプロキシなしで生きることができます。

しかし、合理的なパフォーマンスで多くのエンティティを処理する場合、トラッキングプロキシを変更する代替手段はありません-EF 4.0でEntityObject派生エンティティを使用することを除き(EF 4.1のオプションではありません。DbContext)Entity Frameworkをまったく使用していない。

編集(2012年5月)

それまでの間、スナップショットベースの追跡と比較して 変更追跡プロキシ のパフォーマンスが速くない、またはさらに悪い状況があることを学びました。

変更追跡プロキシを使用する場合のこれらの複雑性のため、推奨される方法は、デフォルトでスナップショットベースの変更追跡を使用し、高いパフォーマンスが必要で、スナップショットベースよりも高速であることが証明された状況でのみ(いくつかのテストを行った後)プロキシを慎重に使用することです変更追跡。

102
Slauma

Entity Framework 5を使用している場合は、必ず パフォーマンスに関する考慮事項 の記事をご覧ください。 Sections 5 NoTracking Queriesおよび8 Loading Related Entitiesは、情報に基づいた決定を下すために必要な情報を提供します。乾杯。

15
duoct

プロキシを使用しないことをお勧めします。動的プロキシ作成は、実行時の型チェックに依存するコンポーネントの破損または複雑化を引き起こします。

たとえば、自動マッピングを構成するときに渡したタイプではなく、エンティティが実行時に動的に生成されたプロキシタイプを持っているため、Automapperは実行時にタイプの不一致/予期しないタイプエラーをスローします。

2
CShark

Automapper 4.2.1を使用します。新しいバージョンにはDynamicMapがありません

var parents = parentsRepo.GetAll().ToList();
Mapper.CreateMap<Parent,ParentDto>();
var parentsDto = Mapper.DynamicMap<List<ParentDto>>(parents);

動的プロキシにはニースの機能がいくつかありますが、実際には多くの奇妙で不明瞭なバグが作成される可能性があります。

たとえば、私のクラスの1つにエンティティのプライベート変数を保持し(バッチプロセスを実装していました)、数百万のレコードをループし、それらをバッチで処理して挿入し、nレコードごとにデータコンテキストを再作成しましたメモリを消去します。私はプライベート変数を使用したことはありませんが、参照IDのみを設定していても、EFはそれを新しいオブジェクトにリンクしていました(ナビゲーションプロパティによる参照がありました)。

これにより、プロセスが実行されている間、すべてのオブジェクトがメモリ内に残りました。プロセスが期待どおりに機能し、メモリとパフォーマンスが通常のレベルに戻るには、AsNoTrackingを使用してプロキシを無効にする必要がありました。プロキシはそれらを作成したコンテキストも参照することに注意してください。これにより、エンティティの巨大なグラフをメモリ内に保持でき、デバッグすることはほとんど不可能です。

したがって、プロキシをグローバルに無効にし、小さくて含まれるコードでプロキシを有効にする必要があると思います。大規模なチームがコーディングしている場合、このような問題を特にデバッグすることは非常に危険で不可能です。

変更の追跡は素晴らしいです。それは、いくつかの場所での使用を正当化するかもしれません。遅延読み込みは、何をしているのかわからない限り、パフォーマンスとシリアル化で大きな問題になることがあります。常に積極的または明示的にロードすることを好みます。

0
Chriss