- 实体框架教程
- 实体框架 - 首页
- 实体框架 - 概述
- 实体框架 - 架构
- 实体框架 - 环境设置
- 实体框架 - 数据库设置
- 实体框架 - 数据模型
- 实体框架 - DbContext
- 实体框架 - 类型
- 实体框架 - 关系
- 实体框架 - 生命周期
- 实体框架 - 代码优先方法
- 实体框架 - 模型优先方法
- 实体框架 - 数据库优先方法
- 实体框架 - 开发方法
- 实体框架 - 数据库操作
- 实体框架 - 并发
- 实体框架 - 事务
- 实体框架 - 视图
- 实体框架 - 索引
- 实体框架 - 存储过程
- 实体框架 - 脱机实体
- 实体框架 - 表值函数
- 实体框架 - 原生SQL
- 实体框架 - 枚举支持
- 实体框架 - 异步查询
- 实体框架 - 持久化
- 实体框架 - 投影查询
- 实体框架 - 命令日志
- 实体框架 - 命令拦截
- 实体框架 - 空间数据类型
- 实体框架 - 继承
- 实体框架 - 迁移
- 实体框架 - 提前加载
- 实体框架 - 延迟加载
- 实体框架 - 显式加载
- 实体框架 - 验证
- 实体框架 - 跟踪更改
- 实体框架 - 彩色实体
- 实体框架 - 代码优先方法
- 实体框架 - 第一个示例
- 实体框架 - 数据注解
- 实体框架 - Fluent API
- 实体框架 - 种子数据库
- 实体框架 - 代码优先迁移
- 实体框架 - 多个DbContext
- 实体框架 - 嵌套实体类型
- 实体框架资源
- 实体框架 - 快速指南
- 实体框架 - 有用资源
- 实体框架 - 讨论
实体框架 - 生命周期
生命周期
上下文的生命周期从实例创建开始,到实例被处置或垃圾回收结束。
在使用ORM时,上下文生命周期是一个非常关键的决策。
上下文就像一个实体缓存,这意味着它保存对所有已加载实体的引用,这可能会导致内存消耗迅速增加,并可能造成内存泄漏。
在下图中,您可以看到从应用程序到数据库通过上下文的数据工作流程的上一级,反之亦然。
实体生命周期
实体生命周期描述了创建、添加、修改、删除等实体的过程。实体在其生命周期中具有许多状态。在查看如何检索实体状态之前,让我们先看看什么是实体状态。状态是类型为System.Data.EntityState的枚举,它声明以下值:
已添加:实体被标记为已添加。
已删除:实体被标记为已删除。
已修改:实体已被修改。
未更改:实体未被修改。
已分离:实体未被跟踪。
实体生命周期中的状态更改
有时实体的状态由上下文自动设置,但也可以由开发人员手动修改。尽管所有从一种状态切换到另一种状态的组合都是可能的,但其中一些是没有意义的。例如,将已添加实体更改为已删除状态,反之亦然。
让我们讨论不同的状态。
未更改状态
当实体未更改时,它绑定到上下文,但它没有被修改。
默认情况下,从数据库检索到的实体处于此状态。
当实体附加到上下文(使用Attach方法)时,它也处于未更改状态。
上下文无法跟踪它未引用的对象的更改,因此当它们被附加时,它假定它们未更改。
已分离状态
已分离是新创建实体的默认状态,因为上下文无法跟踪代码中任何对象的创建。
即使您在上下文的using块内实例化实体,情况也是如此。
即使在禁用跟踪时从数据库检索到的实体也处于已分离状态。
当实体已分离时,它不会绑定到上下文,因此其状态不会被跟踪。
它可以被处置、修改、与其他类结合使用,或以您可能需要的任何其他方式使用。
由于没有上下文跟踪它,因此对实体框架没有意义。
已添加状态
当实体处于已添加状态时,您有几个选项。实际上,您只能将其从上下文中分离。
当然,即使您修改了一些属性,状态仍然是已添加,因为将其移动到已修改、未更改或已删除状态是没有意义的。
这是一个新的实体,并且与数据库中的行没有对应关系。
这是处于这些状态之一的基本先决条件(但此规则不受上下文强制执行)。
已修改状态
当实体被修改时,这意味着它处于未更改状态,然后更改了一些属性。
实体进入已修改状态后,它可以移动到已分离或已删除状态,但即使您手动恢复原始值,它也不能回滚到未更改状态。
它甚至不能更改为已添加,除非您分离并将实体添加到上下文,因为数据库中已经存在具有此ID的行,并且在持久化它时会收到运行时异常。
已删除状态
实体进入已删除状态是因为它未更改或已修改,然后使用了DeleteObject方法。
这是最严格的状态,因为从这种状态更改为除已分离之外的任何其他值都没有意义。
如果您希望在块结束时处置上下文控制的所有资源,请使用using语句。当您使用using语句时,编译器会自动创建一个try/finally块并在finally块中调用dispose。
using (var context = new UniContext()) { var student = new Student { LastName = "Khan", FirstMidName = "Ali", EnrollmentDate = DateTime.Parse("2005-09-01") }; context.Students.Add(student); context.SaveChanges(); }
使用长期运行的上下文时,请考虑以下几点:
随着您将更多对象及其引用加载到内存中,上下文的内存消耗可能会迅速增加。这可能会导致性能问题。
当不再需要上下文时,请记住将其处置。
如果异常导致上下文处于不可恢复的状态,则整个应用程序可能会终止。
随着数据查询和更新之间的时间间隔的增长,遇到与并发相关的问题的可能性会增加。
在使用Web应用程序时,请为每个请求使用一个上下文实例。
在使用Windows Presentation Foundation (WPF)或Windows Forms时,请为每个窗体使用一个上下文实例。这允许您使用上下文提供的更改跟踪功能。
经验法则
Web应用程序
现在,对于Web应用程序,每请求使用一个上下文是一种常见的最佳实践。
在Web应用程序中,我们处理的请求非常短,但包含所有服务器事务,因此这是上下文生存的适当持续时间。
桌面应用程序
对于桌面应用程序(如Win Forms/WPF等),上下文用于每个窗体/对话框/页面。
由于我们不希望将上下文作为应用程序的单例,因此当我们从一个窗体移动到另一个窗体时,我们将将其处置。
通过这种方式,我们将获得上下文的大部分功能,并且不会受到长期运行上下文的负面影响。