Entity Framework ChangeTracker 如何知道 属性 已更改?

How Does the Entity Framework ChangeTracker know that a property has changed?

Entity Framework ChangeTracker 如何知道 属性 发生了变化?这些属性没有高级 setter。我想知道如何跟踪这些变化。

如果您正常使用 DbContext 和 DbSet,则不会向更改跟踪器添加项目。在您可以更改实体的任何 属性 之前,您首先必须获取它。另外如果你想删除它,你必须先获取它。

更改跟踪器保存所有获取的项目,至少在 SaveChanges 之前,但可能在 DbContext 被处置之前,如果您真的想知道,请编写一些测试代码。

ChangeTracker 还包含所有已添加的项目。

可以使用方法 EntriesEntries<...> 访问 ChangeTracker 中提取和添加项目的序列。返回值是一个DbEntityEntries的序列。每个DbEntityEntry都有一个State,表示是Added/Deleted/Modified/Unchanged

获取项目后,其状态为未更改。如果调用 Delete,状态会更改为 Deleted。如果您添加一个对象,则状态如果已添加。困难的部分是Modified,因为您可以在不使用DbSet 的情况下修改项目:

// Student moves to different school:
int jfkSchoolId = schoolContext.Schools
    .Where(school => school.Name = "J.F. Kennedy School")
    .Select(school => school.Id)
    .FirstOrDefault();
var student = schoolContext.Students.Where(student.Id == 100).SingleOrDefault();
student.SchoolId = jfkSchoolId;

ChangeTracker 如何知道您更改了 SchoolId?

幸运的是,DbEntityEntry 包含原始数据库值和当前值。因此,当您请求状态时,它所要做的就是检查它是否已被添加/删除等。大多数状态都很简单,只有当它是 Unchanged 时,获取状态的函数将必须检查所有原始值所有当前值,使用默认值比较器。如果有差异,则状态标记为已更改,因此下次不需要进行值比较。

您无法撤消此操作:状态一旦更改,您将无法取消更改:

int originalSchoolId = myStudent.SchoolId;
myStudent.SchoolId = jfxSchoolId;
var state = dbContext.ChangeTracker.Entries<Students>
    .Where(studentEntity => studentEntity.Entity.Id == myStudent.Id)
    .Select(studentEntity => studentEntity.State)
    .SingleOrDefault();
// state equals Changed, because original value was not 0
// student back to original school
myStudent.SchoolId = originalSchoolId;
// ask the state of this student again:    
state = ...
// state is still changed