自跟踪实体Self-tracking entities
重要
我们不再建议使用自跟踪实体模板。 它将仅继续用于支持现有应用程序。 如果应用程序需要使用断开连接的实体图,请考虑其他替代方案,例如可跟踪实体,它与自跟踪实体类似,社区在更积极地开发这种技术,或使用低级别更改跟踪 API 编写自定义代码。
在基于实体框架的应用程序中,上下文负责跟踪对象中的更改。 然后,使用 SaveChanges 方法将更改保存到数据库。 使用 N 层应用程序时,实体对象通常会从上下文断开连接,用户必须决定如何跟踪更改并向上下文报告这些更改。 自跟踪实体 (STE) 有助于跟踪任意层中的更改,之后可将这些更改重放入上下文中进行保存。
仅当上下文在更改对象图所在的层上不可用时才使用 STE。 如果上下文可用,则无需使用 STE,因为上下文将负责跟踪更改。
此模板项会生成两个 .tt(文本模板)文件:
.tt 文件可生成实体类型、包含自跟踪实体使用的更改跟踪逻辑的 Helper 类以及允许设置自跟踪实体的状态的扩展方法。 .Context.tt 文件生成派生的上下文和扩展类,该类包含 ObjectContext 和 ObjectSet 类的 ApplyChanges 方法。 这些方法检查自跟踪实体图中包含的更改跟踪信息,以推断在数据库中保存这些更改所必须执行的一组操作。
入门Get Started
若要开始操作,请访问自跟踪实体演练页。
使用自跟踪实体时的功能性注意事项Functional Considerations When Working with Self-Tracking Entities
重要
我们不再建议使用自跟踪实体模板。 它将仅继续用于支持现有应用程序。 如果应用程序需要使用断开连接的实体图,请考虑其他替代方案,例如可跟踪实体,它与自跟踪实体类似,社区在更积极地开发这种技术,或使用低级别更改跟踪 API 编写自定义代码。
使用自跟踪实体时应考虑以下事项:
确保您的客户端项目具有对包含实体类型的程序集的引用。 如果您只将服务引用添加到客户端项目,则客户端项目将使用 WCF 代理类型,而不是实际的自跟踪实体类型。 这意味着您将不能获得管理客户端上实体跟踪的自动通知功能。 如果您不希望包含实体类型,则必须手动设置客户端的更改跟踪信息以便将更改发送回服务。
对服务操作的调用应是无状态的,并且创建一个新的对象上下文实例。 同样建议在 using 块中创建对象上下文 。
如果在将客户端上已修改的图发送到服务后想要在客户端上继续使用同一张图,则必须手动循环访问该图,并对每个对象调用 AcceptChanges 方法以重置更改跟踪器 。
如果图中的对象包含具有数据库生成的值(例如,标识值或并发值)的属性,则在调用 SaveChanges 方法后,实体框架将把这些属性的值替换为数据库生成的值 。 可实现服务操作以返回保存的对象或生成的属性值列表,从而将对象发送回客户端。 然后,客户端需要将对象实例或对象属性值替换为从服务操作返回的对象或属性值。
合并多个服务请求的关系图可能会在生成的关系图中引入具有重复键值的对象。 调用 ApplyChanges 方法时,实体框架不会删除具有重复键的对象,但会引发异常 。 为了避免生成具有重复键值的图,请遵循以下博客中所述的模式之一:自跟踪实体:ApplyChanges 和重复实体。
当您通过设置外键属性更改对象之间的关系时,引用导航属性设置为 Null,并且不同步到客户端上的相应主体实体。 将图附加到对象上下文之后(例如,调用 ApplyChanges 方法之后),会同步外键属性和导航属性 。
如果您已对外键关系指定级联删除,则引用导航属性与相应主体对象不同步会是个问题。 如果您删除了主体,则这种删除将不会传播到依赖对象。 如果您已指定级联删除,则使用导航属性更改关系,而不是设置外键属性。
执行延迟加载时不启用自跟踪实体。
自跟踪实体不支持二进制序列化和针对 ASP.NET 状态管理对象的序列化。 但是,您可以自定义此模板来添加二进制序列化支持。 有关详细信息,请参阅将二进制序列化和 ViewState 用于自跟踪实体。
安全注意事项Security Considerations
使用自跟踪实体时,应考虑以下安全注意事项:
- 服务不应信任从不受信任的客户端或通过不受信任的通道检索或更新数据的请求。 客户端必须经身份验证:应使用安全通道或消息信封。 必须验证客户端更新或检索数据的请求,从而确保这些请求符合对于给定方案合法的预期更改。
- 避免将敏感信息用作实体键(例如身份证号码)。 这样可降低意外地将自跟踪实体图中的敏感信息序列化到不完全可信的客户端的可能性。 通过使用独立关联,实体中与正在序列化的键相关的原始键也可能会发送到客户端。
- 为了避免向客户端层传播包含敏感数据的异常消息,应将服务器层上对 ApplyChanges 和 SaveChanges 的调用包装到异常处理代码中 。