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