最初にエンティティの取得を行わずにデータベース内のエンティティを更新するために私が知っている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
.Attach()は、最初にデータベースに移動してレコードを取得してから、変更をそのレコードとマージしませんか?とにかく往復することになります
いいえ 、これをテストできます
using System;
using System.Data.Entity;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
public class Program
{
public static void Main()
{
var movie1 = new Movie { Id = 1, Title = "Godzilla" };
var movie2 = new Movie { Id = 2, Title = "Iron Man" };
using (var context = new MovieDb())
{
/*
context.Database.Log = (s) => {
Console.WriteLine(s);
};
*/
Console.WriteLine("========= Start Add: movie1 ==============");
context.Movies.Add(movie1);
context.SaveChanges();
Console.WriteLine("========= END Add: movie1 ==============");
// LET EF CREATE ALL THE SCHEMAS AND STUFF THEN WE CAN TEST
context.Database.Log = (s) => {
Console.WriteLine(s);
};
Console.WriteLine("========= Start SELECT FIRST movie ==============");
var movie1a = context.Movies.First();
Console.WriteLine("========= End SELECT FIRST movie ==============");
Console.WriteLine("========= Start Attach Movie2 ==============");
context.Movies.Attach(movie2);
Console.WriteLine("========= End Attach Movie2 ==============");
Console.WriteLine("========= Start SELECT Movie2 ==============");
var movie2a = context.Movies.FirstOrDefault(m => m.Id == 2);
Console.WriteLine("========= End SELECT Movie2 ==============");
Console.Write("Movie2a.Id = ");
Console.WriteLine(movie2a == null ? "null" : movie2a.Id.ToString());
}
}
public class MovieDb : DbContext
{
public MovieDb() : base(FiddleHelper.GetConnectionStringSqlServer()) {}
public DbSet<Movie> Movies { get; set; }
}
public class Movie
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Title { get; set; }
}
}
attachがDB呼び出しを行うと、StartAttachMovie2とEndAttachMovie2の間にそれらが表示されます。また、次のように記載されているドキュメントを確認します。
備考
アタッチは、データベースにすでに存在することがわかっているエンティティをコンテキストに再設定するために使用されます。
したがって、SaveChangesは、アタッチされたエンティティがすでに存在していると想定されるため、データベースにアタッチされたエンティティを挿入しようとはしません。
movie2を添付した後、DBから選択を試みることができます。そこにあるべきではありません(EFはそこにあると想定しているだけだからです)。
=========追加を開始:movie1 ==============
========= END追加:movie1 ==============
=========SELECTFIRSTムービーを開始==============
2020年1月15日午後5時29分23秒+00:00に接続を開きました
トップを選択(1)
[c]。[Id]AS[Id]、
[c]。[タイトル]AS[タイトル]
FROM[dbo]。[Movies]AS[c]
-2020年1月15日午後5時29分23秒+00:00に実行
--23ミリ秒で完了し、結果はSqlDataReaderです。
2020年1月15日午後5時29分23秒+00:00に接続を閉じました
=========SELECTFIRSTムービーを終了==============
=========AttachMovie2の開始==============
========= End Attach Movie2 ==============
=========SELECTMovie2を開始==============
2020年1月15日午後5時29分23秒+00:00に接続を開きました
トップを選択(1)
[Extent1]。[Id]AS[Id]、
[Extent1]。[タイトル]AS[タイトル]
FROM[dbo]。[Movies]AS[Extent1]
WHERE 2=[Extent1]。[Id]
-2020年1月15日午後5時29分23秒+00:00に実行
--2ミリ秒で完了し、結果は:SqlDataReader
2020年1月15日午後5時29分23秒+00:00に接続を閉じました
=========SELECTMovie2を終了==============
Movie2a.Id = null
したがって、アタッチ中にSQLが呼び出されず、アタッチ中にエラーメッセージが表示されず、データベースにありません。