通常“自动检测更改”不会有较大的性能影响,也不需要手动去维护状态变更。变更跟踪器
-
DbContext 维护了一个“变更跟踪器 ChangeTracker”用于追踪实体变更;
-
在提交数据库之前,通过调用成员方法DetectChanges 来扫描被跟踪实体的变更情况;
-
将变更实体提交数据库。
哪些实体会被跟踪?.
不是所有实体都会被跟踪。只有明确取出的实体才会被跟踪,比如:
-
xxx.Find()
-
xxx.First()
-
xxx.ToArray()
-
...
EF 也提供了读取实体但不跟踪实体的方法 AsNoTracking,比如:
-
xxx.AsNoTracking().First()
-
xxx.AsNoTracking().ToArray()
-
...
如果需要查看哪些实体被跟踪,可以使用方法
-
context.ChangeTracker.Entries()
DetectChanges
-
当实体被跟踪时,它的原始值(Original Values)会被 ChangeTracker 缓存;
-
当实体被修改时,ChangeTracker 并不会实时发现实体变更,需要调用 DetectChanges 进行扫描;
-
DetectChanges 会扫描所有被跟踪实体,对比当前值(Current Values)与原始值(Original Values)差异;
-
SaveChanges 时会将差异部分提交数据库。
自动检测更改
默认情况下,自动检测更改(AutoDetectChangesEnabled)处于激活状态。
它会在 SaveChanges 时自动调用 DetectChanges,通常也不需要去关闭它。
public virtual bool AutoDetectChangesEnabled { get; set; } = true;
public virtual int SaveChanges() => SaveChanges(acceptAllChangesOnSuccess: true);
public virtual int SaveChanges(bool acceptAllChangesOnSuccess)
{
...
TryDetectChanges();
...
}
private void TryDetectChanges()
{
if (ChangeTracker.AutoDetectChangesEnabled)
{
ChangeTracker.DetectChanges();
}
}
如何优化
框架上,EF Core 相对于早期 EF 已经作出了很多优化。
使用 EF Core 进行应用程序开发时,应尽量跟踪更少的实体对象:
-
不需要跟踪实体时(只读情况),多使用 AsNoTracking,提升 DetectChanges 效率。