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
,它将只会操作修改后的属性。