ユーザーがエンティティのリストを編集できるプロジェクトに取り組んでいます。これらのエンティティをマップしてモデルを表示し、エディターフィールドで表示します。ユーザーが送信ボタンを押すと、各モデルを調べて次のように更新します。
foreach (var viewModel in viewModels)
{
//Find the database model and set the value and update
var entity = unit.EntityRepository.GetByID(fieldModel.ID);
entity.Value = viewModel.Value;
unit.EntityRepository.Update(entity);
}
上記のコードは機能しますが、ご覧のとおり、すべてのエンティティに対してデータベースを2回ヒットする必要があります(1回取得し、もう1回更新する)。 Entity Frameworkを使用してこれを行うより効率的な方法はありますか?更新ごとに個別のSQLステートメントが生成されることに気付きました。ループの終了後にすべての更新をコミットする方法はありますか?
以下は、最初にエンティティを取得せずにデータベース内のエンティティを更新する2つの方法です。
//Assuming person is detached from the context
//for both examples
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime BornOn { get; set; }
}
public void UpdatePerson(Person person)
{
this.Context.Persons.Attach(person)
DbEntityEntry<Person> entry = Context.Entry(person);
entry.State = System.Data.EntityState.Modified;
Context.SaveChanges();
}
生じるはずです:
Update [schema].[table]
Set Name = @p__linq__0, BornOn = @p__linq__1
Where id = @p__linq__2
または、必要に応じてフィールドを指定することもできます(列の数が多いテーブルに適しているか、セキュリティ上の理由から特定の列のみを更新できます:
public void UpdatePersonNameOnly(Person person)
{
this.Context.Persons.Attach(person)
DbEntityEntry<Person> entry = Context.Entry(person);
entry.Property(e => e.Name).IsModified = true;
Context.SaveChanges();
}
生じるはずです:
Update [schema].[table]
Set Name = @p__linq__0
Where id = @p__linq__1
クエリを最小限に抑えるには、次の方法を試してください。
using (var ctx = new MyContext())
{
var entityDict = ctx.Entities
.Where(e => viewModels.Select(v => v.ID).Contains(e.ID))
.ToDictionary(e => e.ID); // one DB query
foreach (var viewModel in viewModels)
{
Entity entity;
if (entityDict.TryGetValue(viewModel.ID, out entity))
entity.Value = viewModel.Value;
}
ctx.SaveChanges(); //single transaction with multiple UPDATE statements
}
Contains
のリストが非常に長い場合は、viewModels
が遅くなる可能性があることに注意してください ただし、単一のクエリのみを実行します。