实体框架附加/更新混淆(EF Core)

时间:2018-06-05 14:41:14

标签: c# entity-framework sql-update

我对EF方法“附加”和“更新”只有一点混淆。

据我所知,当调用“Update”时,特定实体中的每个属性都会被修改。

另一方面,“Attach”方法在“未修改”状态下启动实体。然后,当对特定属性执行操作时,仅修改该特定属性。因此,“附加”对于单个属性更改更有用,并且当您想要更新实体中的每个属性时,“更新”更有用(我理解这可能是错误的。)

然而,我不明白的是,当在属性更改期间调用这两种方法时,会发生什么。例如,考虑一个名为“students”的表的示例:

_database.students.City = "Calgary";
_database.students.Name = "John Smith";
_database.SaveChanges();

由于我们未将实体中的任何属性标记为已修改,因此上述代码生成的查询将如何不同?

2 个答案:

答案 0 :(得分:4)

在下面的示例中,实体是通过上下文获得的,因此上下文立即开始对其进行跟踪。当您更改跟踪实体的属性值时,上下文会将实体的EntityState更改为Modified,并且ChangeTracker记录旧属性值和新属性值。调用SaveChanges时,数据库将生成并执行UPDATE语句。

var author = context.Authors.First(a => a.AuthorId == 1);
author.FirstName = "Bill";
context.SaveChanges();

由于ChangeTracker跟踪哪些属性已被修改,因此上下文将发出一条SQL语句,该语句仅更新那些已更改的属性:

exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Authors] SET [FirstName] = @p0
WHERE [AuthorId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 nvarchar(4000)',@p1=1,@p0=N'Bill'

DbContext更新

DbContext类提供用于处理单个或多个实体的Update和UpdateRange方法。

public void Save(Author author)
{
    context.Update(author);
    context.SaveChanges();
}

与设置实体的状态一样,此方法导致上下文将其跟踪为已修改实体。再一次,上下文没有任何方法来标识哪些属性值已更改,并且将生成SQL以更新所有属性。该方法与显式设置State属性的区别在于,上下文将开始跟踪处于Modified状态的任何相关实体(例如本示例中的书籍集合),从而为每个实体生成UPDATE语句。 。如果相关实体未分配键值,则将其标记为“已添加”,并生成INSERT语句。

DBContext Attach

在实体上使用Attach方法时,其状态将设置为“不变”,这将导致根本不生成任何数据库命令。定义了键值的所有其他可达实体也将设置为“不变”。那些没有键值的标记为已添加。但是,既然上下文正在跟踪实体,那么您可以通知上下文已修改了哪些属性,以便生成用于更新这些值的正确SQL:

var context = new TestContext();
var author = new Author {
    AuthorId = 1,
    FirstName = "William",
    LastName = "Shakespeare"
};
author.Books.Add(new Book {BookId = 1, Title = "Othello" });
context.Attach(author);
context.Entry(author).Property("FirstName").IsModified = true;
context.SaveChanges();

上面的代码将导致author实体被标记为Modified,并且生成SQL以仅更新FirstName属性:

exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Authors] SET [FirstName] = @p0
WHERE [AuthorId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 nvarchar(4000)',@p1=1,@p0=N'William'

参考:Read more

答案 1 :(得分:3)

请考虑以下代码:

students entity = new students() {
    Id = 1,
    City = "New York",
    Name = "Sam"
};
using(SomeContext ctx = new SomeContext())
{
    ctx.Entry(entity).State = EntityState.Modified;
    ctx.SaveChanges();
}

假设我们在数据库中有一个id = 1的记录,上面的代码将更新数据库中的该实体。

当您知道某个实体已经存在于数据库中但希望在您已经进行更改时将状态更改为已修改时,将使用

Attach