C# EF跟踪与非跟踪

C# EF跟踪与非跟踪,c#,entity-framework,C#,Entity Framework,我希望何时在WebAPI中启用跟踪以及何时禁用跟踪?似乎我总是想用这个: context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; 使用我的DbContext,只有当我需要持久化一个对象时,我才会将该对象标记为已修改。你能给我一个具体的例子,当我需要启用跟踪和当我希望它被禁用? 如果您正在投影到viewmodels和/或通过网络发送等,请感谢。。。跟踪不会有什么不同,只是对性能的轻微影响 如果

我希望何时在WebAPI中启用跟踪以及何时禁用跟踪?似乎我总是想用这个:

context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
使用我的
DbContext
,只有当我需要持久化一个对象时,我才会将该对象标记为已修改。你能给我一个具体的例子,当我需要启用跟踪和当我希望它被禁用? 如果您正在投影到viewmodels和/或通过网络发送等,请感谢。。。跟踪不会有什么不同,只是对性能的轻微影响

如果您正在执行更复杂的查询,将数据拉入内存并对其进行变异,那么跟踪将更有意义,因为它允许您修改实体并再次调用
SaveChanges


就这么简单。

首先,让我们了解跟踪到底是什么,这是一本关于跟踪的好读物,但简而言之:

跟踪行为控制实体框架核心是否保持 有关更改跟踪器中实体实例的信息。如果 如果跟踪实体,则将跟踪在该实体中检测到的任何更改 在SaveChanges()期间保留到数据库

正如您在上面的示例中所看到的,如果跟踪查询(这是默认行为),您甚至不需要将对象标记为已修改,因为此对象是由它所附加的上下文检索的,并且上下文将注意到在其上执行的更改并将其持久化。我们调用了
SaveChanges()

因此,为了回答您的问题:这取决于场景,如果您确定不会修改检索到的数据,并且不需要保留可能对其执行的任何更改,那么使用跟踪查询是没有意义的,事实上,如果使用无跟踪查询,将有助于提高性能

将无跟踪查询视为只读数据,您只想检索以显示给用户或从中提取一些信息


上面提到的是EF核心,但跟踪与无跟踪的概念是相同的,即使在其他ORM中也是如此

当您进行提取,然后对提取的同一对象进行更改(更新)时,需要进行跟踪。现在,如果您将该对象保存回DB,则跟踪是有意义的


WebAPI中从来没有这种情况。

我使用的唯一上下文实例
QueryTrackingBehavior。NoTracking
是报告上下文,而不是API上下文,除非适用于该上下文的API完全是只读的

NoTracking
将为数据读取操作提供标称速度提升

您可以使用
NoTracking
进行更新操作,但您将需要一些额外的代码,并且会对更新产生名义上的惩罚。如果您只构建附加(插入,不更新),则
NoTracking
不提供任何惩罚

原因:当EF加载带有跟踪的实体时,会发生两种情况。首先,将引用加载到本地缓存中。其次,使用代理跟踪实体上字段的更新

给定接受记录实体新消息的更新:

void UpdateMessage(int recordId, string message);
跟踪:

void UpdateMessage(int recordId, string message)
{
    using(var context = new AppContext())
    {
         var record = context.Records.Single(x => x.RecordId == recordId);
         record.Message = message;
         context.SaveChanges();
    }
}
void UpdateMessage(int recordId, string message)
{
    using(var context = new AppContext())
    {
         var record = context.Records.AsNoTracking().Single(x => x.RecordId == recordId);
         record.Message = message;
         context.Update(record); // or Attach() and set Modified state.
         context.SaveChanges();
    }
}
无跟踪:

void UpdateMessage(int recordId, string message)
{
    using(var context = new AppContext())
    {
         var record = context.Records.Single(x => x.RecordId == recordId);
         record.Message = message;
         context.SaveChanges();
    }
}
void UpdateMessage(int recordId, string message)
{
    using(var context = new AppContext())
    {
         var record = context.Records.AsNoTracking().Single(x => x.RecordId == recordId);
         record.Message = message;
         context.Update(record); // or Attach() and set Modified state.
         context.SaveChanges();
    }
}
这些在表面上看起来非常相似,但在发动机罩下会出现明显的差异:

在第一种情况下,EF将生成类似于以下内容的SQL语句:

UPDATE tblRecords SET Message = @1 WHERE RecordId = @0
在第二种情况下,EF将生成:

UPDATE tblRecords SET Message = @1, SomeField = @2, SomeOtherField = @3, CreatedAt = @4, CreatedBy = @5 WHERE RecordId = @0
当获取未跟踪的实体并“更新”它们时,EF不知道发生了什么变化,所以每一列都会更新。通过跟踪,查询中将仅显示已更新的字段。对于较大的实体,这是显而易见的

插入(包括仅附加系统的插入)不受影响,因为它们无论如何都会包括所有列