entity framework core是如何实现上下文追踪的?

通常“自动检测更改”不会有较大的性能影响,也不需要手动去维护状态变更。变更跟踪器

  1. DbContext 维护了一个“变更跟踪器 ChangeTracker”用于追踪实体变更;

  2. 在提交数据库之前,通过调用成员方法DetectChanges 来扫描被跟踪实体的变更情况;

  3. 将变更实体提交数据库。

哪些实体会被跟踪?.

不是所有实体都会被跟踪。只有明确取出的实体才会被跟踪,比如:

  • xxx.Find()

  • xxx.First()

  • xxx.ToArray()

  • ...

EF 也提供了读取实体但不跟踪实体的方法 AsNoTracking,比如:

  • xxx.AsNoTracking().First()

  • xxx.AsNoTracking().ToArray()

  • ...

如果需要查看哪些实体被跟踪,可以使用方法

  • context.ChangeTracker.Entries()

DetectChanges

  1. 当实体被跟踪时,它的原始值(Original Values)会被 ChangeTracker 缓存;

  2. 当实体被修改时,ChangeTracker 并不会实时发现实体变更,需要调用 DetectChanges 进行扫描;

  3. DetectChanges 会扫描所有被跟踪实体,对比当前值(Current Values)与原始值(Original Values)差异;

  4. 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 效率。