我知道有两种方法可以在不先检索实体的情况下更新数据库中的实体:
//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() 不是先去数据库检索记录,然后再将更改与它合并吗?所以你最终还是要往返
没有。 We can test this
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 调用,我们将在 Start Attach Movie2 和 End Attach Movie2 之间看到它们。我们还验证了以下说明的文档:
备注
附加用于使用已知数据库中已存在的实体重新填充上下文。
因此,SaveChanges 不会尝试将附加实体插入到数据库中,因为假定它已经存在。
附加movie2后,我们可以尝试从数据库中选择它。它不应该存在(因为 EF 只假定它存在)。
========= 开始添加:movie1 ==============
========= END 添加:movie1 ==============
========= 开始选择第一部电影 ==============
在 2020 年 1 月 15 日下午 5:29:23 +00:00 打开连接
选择顶部(1)
[c].[Id] AS [Id],
[c].[标题] AS [标题]
来自 [dbo].[电影] 作为 [c]
-- 执行于 1/15/2020 5:29:23 PM +00:00
-- 在 23 毫秒内完成,结果为:SqlDataReader
2020 年 1 月 15 日下午 5:29:23 +00:00 关闭连接
========= 结束选择第一部电影 ==============
========= 开始附加影片2 ==============
========= End Attach Movie2 ==============
========= 开始选择电影2 ==============
在 2020 年 1 月 15 日下午 5:29:23 +00:00 打开连接
选择顶部(1)
[Extent1].[Id] AS [Id],
[Extent1].[标题] AS [标题]
FROM [dbo].[电影] AS [Extent1]
WHERE 2 = [Extent1].[Id]
-- 执行于 1/15/2020 5:29:23 PM +00:00
-- 在 2 毫秒内完成,结果为:SqlDataReader
2020 年 1 月 15 日下午 5:29:23 +00:00 关闭连接
========= End SELECT Movie2 ==============
Movie2a.Id = null
所以在附加过程中没有调用 SQL,附加它没有错误消息,它不在数据库中。