自動変更検出

ほとんどの 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

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

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

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 回だけ変更を自動的に検出します。