2017-02-07 6 views
1

現在、取得されたデータベースレコードは、IDキーを格納する簡易モデルに読み込まれます。いくつかの計算の後、元のレコードの1つまたは複数のフィールドを更新する必要があります。EF:IDでフィールドを更新するベスト/最速の方法

モデルは非常に大きく(文字列の多い)、エントリ数は表あたり100,000を超える可能性があります。したがって、それらをメモリにロードすると、OutOfMemoryExceptionが発生します。

class Model // Database-Table 
{ 
    public Int Id { get; set; } 
    public int Field { get; set; } 
} 

class SimpleModel 
{ 
    int Id; 
    int Field; 
} 

void Update(SimpleModel[] simpleModels) 
{ 
    using(var ctx = new DbContext()) 
    { 
     foreach(var simpleModel in simpleModels) 
     { 
      var entry = ctx.ModelTable 
       .Where(x => x.Id == simpleModel.Id) 
       .FirstOrDefault(); 

      if(entry == null) 
       continue; 

      ctx.ModelTable.Attach(entry); 

      entry.Field = simpleModel.Field; 
     } 

     if(ctx.ChangeTracker.HasChanges()) 
      ctx.SaveChanges(); 
    } 
} 

しかし、これは非常に遅いです。 EntityFrameworkを使用して、これを高速化する方法はありますか?(直接のstring-sql-queriesは必要ありません)

答えて

3

FirstOrDefault()を使用するたびに、新しいデータベースクエリを実行します。

var ids = simpleModels.Select(sm => sm.Id); 
var entries = ctx.ModelTable.Where(m => ids.Contains(m.Id)).ToList(); 
// or 
var entriesById = ctx.ModelTable.Where(m => ids.Contains(m.Id)).ToDictionary(x => x.Id); 

さらに、データベースクエリを追加することなく、読み込まれたエントリで作業することができます。例えば。

foreach(var simpleModel in simpleModels) 
{ 
     Model entry; 
     if (!entriesById.TryGetValue(simpleModel.Id, out entry)) 
     continue; 

     entry.Field = simpleModel.Field; 
} 
+0

ありがとうございます。しかし、これは大きなセット(> 100kエントリ)では機能しません。 OutOfMemoryExceptionを回避するにはどうすればよいですか?私は手動でそれらをバッチする必要がありますか?私は私の質問を更新し、そこにこれを言及しました – user5997884

+0

私はあなたのアプローチが好きです。各行のデータベースとのやりとりをたくさんするのではなく、データを読み込むためのものと読み上げるためのものSQL BulkUpdate –

+1

@ user5997884私は手動バッチ処理に行きます。 'ids'配列の部分に対して同じロード更新シナリオを繰り返すだけです。たとえば、1000回進むことができます。 –

関連する問題