实体框架 - 生命周期
生命周期
上下文的生命周期从实例创建时开始,到实例被处置或垃圾收集时结束。
上下文生命周期是我们使用 ORM 时需要做出的一个非常重要的决定。
上下文的性能类似于实体缓存,因此它保存了对所有已加载实体的引用,这些实体的内存消耗可能会快速增长,还可能导致内存泄漏。
在下图中,您可以看到通过上下文从应用程序到数据库以及反之亦然的数据工作流的上层。
实体生命周期
实体生命周期描述了创建、添加和删除实体的过程。修改、删除等。实体在其生命周期内有许多状态。在了解如何检索实体状态之前,让我们先看看什么是实体状态。状态是 System.Data.EntityState 类型的枚举,它声明以下值 −
Added(已添加):实体被标记为已添加。
Deleted(已删除):实体被标记为已删除。
Modified(已修改):实体已被修改。
Unchanged(未更改):实体未被修改。
Detached(已分离):实体未被跟踪。
实体生命周期中的状态变化
有时实体的状态由上下文自动设置,但也可以由开发人员手动修改。尽管从一个状态切换到另一个状态的所有组合都是可能的,但其中一些是没有意义的。例如,将 Added 实体转换为 Deleted 状态,反之亦然。
让我们讨论一下不同的状态。
Unchanged 未更改状态
当实体处于"未更改"状态时,它已绑定到上下文,但尚未被修改。
默认情况下,从数据库检索到的实体处于此状态。
当实体附加到上下文(使用 Attach 方法)时,它同样处于"未更改"状态。
上下文无法跟踪它未引用的对象的变化,因此当它们被附加时,它假定它们是"未更改"的。
Detached 分离状态
分离是新创建的实体,因为上下文无法跟踪代码中任何对象的创建。
即使您在上下文的使用块内实例化实体,情况也是如此。
当跟踪被禁用时,分离甚至是从数据库检索的实体的状态。
当实体分离时,它不会绑定到上下文,因此不会跟踪其状态。
它可以被处理、修改、与其他类结合使用,或以您可能需要的任何其他方式使用。
因为没有上下文跟踪它,所以它对实体框架没有任何意义。
Added 已添加状态
当实体处于已添加状态时,您只有很少的选择。实际上,您只能将其从上下文中分离出来。
当然,即使您修改了某些属性,状态仍为已添加,因为将其移动到已修改、未更改或已删除是没有意义的。
这是一个新实体,与数据库中的行没有对应关系。
这是处于这些状态之一的基本先决条件(但此规则不受上下文强制执行)。
Modified 已修改状态
当实体被修改时,这意味着它处于未更改状态,然后某些属性被更改。
实体进入已修改状态后,可以移动到已分离或已删除状态状态,但即使您手动恢复原始值,它也无法回滚到 Unchanged 状态。
它甚至不能更改为 Added,除非您分离并将实体添加到上下文,因为数据库中已经存在具有此 ID 的行,并且在持久化它时会收到运行时异常。
Deleted 状态
实体进入 Deleted 状态,因为它是 Unchanged 或 Modified,然后使用了 DeleteObject 方法。
这是最严格的状态,因为从此状态更改为 Detached 以外的任何其他值都是没有意义的。
如果您希望在块末尾处置上下文控制的所有资源,请使用 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 窗体时,每个窗体使用一个上下文实例。这样您就可以使用上下文提供的更改跟踪功能。
经验法则
Web 应用程序
对于 Web 应用程序来说,上下文按请求使用是一种常见且最佳实践。
在 Web 应用程序中,我们处理的请求非常短,但会保留所有服务器事务,因此它们是上下文的适当生存期。
桌面应用程序
对于桌面应用程序,如 Win Forms/WPF 等,上下文按窗体/对话框/页面使用。
由于我们不想将上下文作为应用程序的单例,因此当我们从一个窗体移动到另一个窗体时,我们将处理它。
通过这种方式,我们将获得很多上下文的能力,并且不会受到长期运行上下文的影响。