标识解析、状态管理和更改跟踪(实体框架)
ObjectContext 表示内存中对象的容器。 借助其他类和接口的帮助,对象上下文可以管理对象的标识、状态、对象属性的原始值和当前值以及跟踪对缓存中每个对象所做的更改。 有关如何将对象附加到对象上下文的信息,请参见附加和分离对象(实体框架)。 本主题讨论对象上下文如何管理更改跟踪、标识解析和状态管理。
更改跟踪
对象图的更改跟踪信息存储在 ObjectStateEntry 对象中,这些对象是由 ObjectContext 为每个附加的对象创建的。 ObjectStateEntry 对象存储实体的以下信息:
用于确定实体的标识的 EntityKey。
对象的 EntityState
相关对象的信息
实体集名称
实体属性的 CurrentValues 和 OriginalValues(处于 Added 状态的对象没有原始值)
实体的已修改属性的名称。
若要查看某个属性的值在对 SaveChanges 的各次调用之间是否已更改,可查询由 GetModifiedProperties 方法返回的已更改属性名称的集合。
注意: |
---|
如果您在使用 POCO 实体时没有使用更改跟踪代理,则在调用 GetModifiedProperties 之前必须调用 DetectChanges。 |
在实体分离后,将从对象上下文中移除相应的 ObjectStateEntry 对象。
ObjectStateEntry 对象由 ObjectStateManager 进行管理。 每个对象上下文都有一个 ObjectStateManager 的实例。 若要获取指定实体的 ObjectStateEntry 对象,请对 ObjectStateManager 使用以下方法之一:TryGetObjectStateEntry、GetObjectStateEntry 或 GetObjectStateEntries 方法。
对象上下文将在实体框架 生成的实体的属性和 POCO 更改跟踪代理对象的属性发生更改时得到通知,并在 ObjectStateEntry 中更新对象的状态和属性的值。 更改报告模型涉及使用 IEntityChangeTracker 接口报告对属性的挂起更改、设置属性以及随后报告更改已完成。 ObjectStateEntry 管理不具有更改跟踪代理对象的 POCO 实体的方法与管理复杂类型对象的实体的方法不同。 有关更多信息,请参见跟踪 POCO 实体中的更改(实体框架)。
对象上下文使用 ObjectStateEntry 对象中的信息将数据保存到数据源。 有关更多信息,请参见保存更改和管理并发(实体框架)和如何:在保存更改时执行业务逻辑(实体框架)。
标识解析和合并选项
实体框架 只维护缓存中具有特定实体键的对象的单个实例。 EntityKey 对象是不可变对象,表示对象的标识。 实体键用于在对象上下文中执行标识解析。 有关更多信息,请参见使用实体键(实体框架)。 如果已跟踪具有相同标识的实体,则将根据查询的 MergeOption 合并来自数据源的数据与状态管理器中已存在的数据。
下表显示了可能的合并选项:
成员 | 说明 |
---|---|
将对象上下文中不存在的对象附加到上下文。 如果某个对象已存在于上下文中,则不会使用数据源值覆盖该对象的属性在对应项中的当前值和原始值。 该对象对应的项的状态以及该对象在对应项中的属性的状态不会更改。 AppendOnly 为默认合并选项。 |
|
将对象上下文中不存在的对象附加到上下文。 如果某个对象已存在于上下文中,则不会使用数据源值覆盖该对象的属性在相应项中的当前值和原始值。 该对象的对应项的状态设置为 Unchanged,并且不会将任何属性标记为已修改。 |
|
将对象上下文中不存在的对象附加到上下文。 如果该实体的状态为 Unchanged,则会使用数据源值覆盖对应项中的当前值和原始值。 该实体的状态保持为 Unchanged,并且不会将任何属性标记为已修改。 如果该实体的状态为 Modified,则不会使用数据源值覆盖已修改属性的当前值。 将使用数据源中的值覆盖未修改属性的原始值。 在 .NET Framework 4 版本中,实体框架 将未修改属性的当前值与从数据源返回的值进行比较。 如果值不相同,则将该属性标记为已修改。 在 .NET Framework 3.5 SP1 版本中,即使数据源中的值不相同,实体框架 也不会将该属性标记为已修改。 调用 SaveChanges 时,只会将已修改的属性保存到数据源中。 若要保留 3.5 SP1 行为,请将 UseLegacyPreserveChangesBehavior 设置为 true。 在本地上下文中保留更改时,可以使用 PreserveChanges 解决开放式并发异常。 有关更多信息,请参见保存更改和管理并发(实体框架)。 |
|
对象保持为 Detached 状态,也不在 ObjectStateManager 中进行跟踪。 但是,实体框架 生成的实体和具有代理的 POCO 实体将维护对对象上下文的引用,以方便加载相关对象。 |
实体状态
对象上下文必须了解对象的状态以便将更改保存回数据源。 ObjectStateEntry 对象存储 EntityState 信息。 ObjectContext 的 SaveChanges 方法将处理附加到上下文的实体,并根据每个对象的 EntityState 更新数据源。 有关更多信息,请参见创建、添加、修改和删除对象(实体框架)。 下表显示对象可能的状态:
成员 | 说明 |
---|---|
Added |
该对象是已添加到对象上下文的新对象,但尚未调用 SaveChanges 方法。 在保存更改后,对象状态更改为 Unchanged。 处于 Added 状态的对象在 ObjectStateEntry 中没有原始值。 |
已从对象上下文中删除该对象。 在保存更改后,对象状态更改为 Detached。 |
|
Detached |
该对象存在但未被跟踪。 在创建实体之后、但将其添加到对象上下文之前,该实体处于此状态。 通过调用 Detach 方法从上下文中移除实体后,或者使用 NoTrackingMergeOption 加载实体后,该实体也会处于此状态。 没有与处于 Detached 状态的对象关联的 ObjectStateEntry 实体。 |
Modified |
对象上的一个标量属性已修改,但尚未调用 SaveChanges 方法。 在没有更改跟踪代理的 POCO 实体中,如果调用 DetectChanges 方法,则已修改属性的状态将更改为 Modified。 在保存更改后,对象状态更改为 Unchanged。 |
Unchanged |
自附加到上下文中后,或自上次调用 SaveChanges 方法后,该对象尚未修改。 |
对象上下文中的对象状态由 ObjectStateManager 管理。 若要确定对象的状态,请调用以下 ObjectStateManager 方法之一:TryGetObjectStateEntry、GetObjectStateEntry 或 GetObjectStateEntries。 ObjectStateEntry 的 State 属性定义对象的状态。