以下是我所知道的在不先检索实体的情况下更新数据库中的实体的两种方法:
//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 进行任何数据库调用,我们将在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 [标题]
FROM [dbo].[电影] AS [c]
-- 执行于 2020 年 1 月 15 日下午 5:29:23 +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]
其中 2 = [Extent1].[Id]
-- 执行于 2020 年 1 月 15 日下午 5:29:23 +00:00
-- 在 2 毫秒内完成,结果为:SqlDataReader
2020 年 1 月 15 日下午 5:29:23 +00:00 关闭连接
=========结束选择电影2 ===============
Movie2a.Id = null
所以在附加过程中没有调用 SQL,附加它没有错误消息,它不在数据库中。