DbSet.Attach(实体)与DbContext.Entry(实体).State = EntityState.Modified

当我在一个独立的场景,并从我映射到一个实体来保存它的客户端得到一个dto我这样做:

context.Entry(entity).State = EntityState.Modified; context.SaveChanges(); 

那么什么是DbSet.Attach(entity)

或者为什么当EntityState.Modified已经附加实体时应该使用.Attach方法?

当你做context.Entry(entity).State = EntityState.Modified; ,您不仅将实体附加到DbContext ,还将整个实体标记为脏。 这意味着当您执行context.SaveChanges() ,EF将生成更新语句,该语句将更新实体的所有字段。

这并不总是需要的。

另一方面, DbSet.Attach(entity)将实体附加到上下文而不将其标记为脏。 它相当于做context.Entry(entity).State = EntityState.Unchanged;

当以这种方式附加时,除非您继续更新实体上的属性,否则下次您调用context.SaveChanges() ,EF将不会为此实体生成数据库更新。

即使您计划对实体进行更新,如果实体具有很多属性(db列),但只想更新一些实体,则可能会发现执行DbSet.Attach(entity)是有利的,那么只更新需要更新的几个属性。 这样做会从EF生成更有效的更新语句。 EF只会更新您修改的属性(与context.Entry(entity).State = EntityState.Modified;这将导致所有属性/列被更新)

相关文档: 添加/附加和实体状态 。

代码示例

假设你有以下实体:

 public class Person { public int Id { get; set; } // primary key public string FirstName { get; set; } public string LastName { get; set; } } 

如果你的代码如下所示:

 context.Entry(personEntity).State = EntityState.Modified; context.SaveChanges(); 

生成的SQL将如下所示:

 UPDATE person SET FirstName = 'whatever first name is', LastName = 'whatever last name is' WHERE Id = 123; -- whatever Id is. 

请注意,上述更新语句将如何更新所有列,而不pipe您是否实际更改了值。

相反,如果你的代码使用“正常”附加这样的:

 context.People.Attach(personEntity); // State = Unchanged personEntity.FirstName = "John"; // State = Modified, and only the FirstName property is dirty. context.SaveChanges(); 

那么生成的更新语句是不同的:

 UPDATE person SET FirstName = 'John' WHERE Id = 123; -- whatever Id is. 

正如你所看到的,更新语句只会更新将实体附加到上下文后实际更改的值。 根据您的表格结构,这可能会产生积极的性能影响。

现在,哪个选项对你更好,完全取决于你正在做什么。

当您使用DbSet.Update方法时,entity framework将您的实体的所有属性标记为EntityState.Modified ,以便跟踪它们。 如果只想更改一些属性,而不是全部,则使用DbSet.Attach 。 此方法使您的所有属性EntityState.Unchanged ,因此您必须使您的属性,您要更新EntityState.Modified 。 因此,当应用程序命中DbContext.SaveChanges ,它将只会操作修改后的属性。