変更の自動検出

ほとんどの POCO エンティティを使用する場合、エンティティがどのように変更されたか (したがって、どの更新プログラムをデータベースに送信する必要がありますか) の決定は、変更の検出アルゴリズムによって処理されます。 変更の検出は、エンティティの現在のプロパティ値と、エンティティのクエリまたはアタッチ時にスナップショットに格納される元のプロパティ値の違いを検出することによって機能します。 このトピックで示す手法は、Code First と EF Designer で作成されたモデルにも同様に適用されます。

既定では、Entity Framework では、次のメソッドが呼び出されると、変更の検出が自動的に実行されます。

  • DbSet.Find
  • DbSet.Local
  • DbSet.Add
  • DbSet.AddRange
  • DbSet.Remove
  • DbSet.RemoveRange
  • DbSet.Attach
  • DbContext.SaveChanges
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries

変更の自動検出を無効にする

コンテキスト内の多数のエンティティを追跡していて、ループ内でこれらのメソッドの 1 つを何度も呼び出す場合は、ループの期間中に変更の検出をオフにすることで、パフォーマンスが大幅に向上する可能性があります。 例えば次が挙げられます。

using (var context = new BloggingContext())
{
    try
    {
        context.Configuration.AutoDetectChangesEnabled = false;

        // Make many calls in a loop
        foreach (var blog in aLotOfBlogs)
        {
            context.Blogs.Add(blog);
        }
    }
    finally
    {
        context.Configuration.AutoDetectChangesEnabled = true;
    }
}

ループ後に変更の検出を再度有効にすることを忘れないでください。ループ内のコードが例外をスローした場合でも、try/finally を使用して常に再有効化されるようにしました。

無効にして再度有効にする代わりに、変更の自動検出を常にオフにしておき、context.ChangeTracker.DetectChanges を明示的に呼び出すか、変更追跡プロキシを確実に使用します。 どちらのオプションも高度であり、アプリケーションに微妙なバグを簡単に導入できるため、慎重に使用してください。

コンテキストに対して多数のオブジェクトを追加または削除する必要がある場合は、DbSet.AddRange と DbSet.RemoveRange の使用を検討してください。 このメソッドは、追加操作または削除操作が完了した後、1 回だけ変更を自動的に検出します。