使用 DbContext

为使用 Entity Framework 来查询、插入、更新和删除使用 .NET 对象的数据,首先需要创建模型来将模型中定义的实体和关系映射到数据库中的表。

创建模型后,应用程序所交互的主要类是 System.Data.Entity.DbContext(通常称为上下文类)。 可以使用与模型关联的 DbContext 来执行以下操作:

  • 编写和执行查询
  • 将查询结果具体化为实体对象
  • 跟踪对这些对象所做的更改
  • 将对象更改保存回数据库
  • 将内存中的对象绑定到 UI 控件

本页面提供了有关如何管理上下文类的一些指导。

定义 DbContext 派生类

使用上下文的推荐方法如下:定义派生自 DbContext 的类,然后公开表示上下文中一系列指定实体的 DbSet 属性。 如果使用的是 EF Designer,则会自动生成上下文。 如果使用的是 Code First,通常需要自行编写上下文。

public class ProductContext : DbContext
{
    public DbSet<Category> Categories { get; set; }
    public DbSet<Product> Products { get; set; }
}

获得上下文后,将通过这些属性在上下文中查询、添加(使用 AddAttach 方法)或删除(使用 Remove)实体。 访问上下文对象上的 DbSet 属性表示开始进行查询,返回指定类型的所有实体。 请注意,仅访问属性不会执行查询。 在以下情况下,将执行查询:

  • foreach (C#) 或 For Each (Visual Basic) 语句枚举对象。
  • 查询是一组操作(例如 ToArrayToDictionaryToList)的枚举对象。
  • 在查询的最外面部分中指定 LINQ 运算符,例如 FirstAny
  • 如果未发现具有指定键的实体已加载到上下文中,调用以下方法之一:Load 扩展方法、DbEntityEntry.ReloadDatabase.ExecuteSqlCommandDbSet<T>.Find

生存期

上下文的生存期从创建实例时开始,并在释放实例或对实例进行垃圾回收时结束。 如果要在块的末尾释放上下文控制的所有资源,请使用 using。 在使用 using 时,编译器将自动创建一个 try/finally 块并在 finally 块中调用释放操作

public void UseProducts()
{
    using (var context = new ProductContext())
    {     
        // Perform data access using the context
    }
}

下面提供了一些用于确定上下文的生存期的一般准则:

  • 在使用 Web 应用程序时,针对每个请求使用一个上下文实例。
  • 在使用 Windows Presentation Foundation (WPF) 或 Windows 窗体时,针对每个窗体使用一个上下文实例。 这使您能够使用上下文所提供的更改跟踪功能。
  • 如果上下文实例是由依赖关系注入容器创建的,则通常由该容器负责释放上下文。
  • 如果上下文是在应用程序代码中创建的,请记住不再需要上下文时将其释放。
  • 在使用长时间运行的上下文时,请考虑以下事项:
    • 随着在内存中加载更多的对象及其引用,上下文对内存的占用可能会快速增长。 这可能会导致性能问题。
    • 上下文不是线程安全的,因此不应在同时使用上下文的多个线程之间共享上下文。
    • 如果某个异常导致上下文处于不可恢复的状态,则整个应用程序可能会终止。
    • 随着查询数据的时间和更新数据的时间的差距增大,出现与并发性相关的问题的可能性将会增加。

连接

默认情况下,上下文管理与数据库的连接。 上下文将根据需要打开和关闭连接。 例如,上下文将打开连接来执行查询,并在处理所有的结果集之后关闭连接。

在某些情况下,您需要加强控制应在哪些情况下打开和关闭连接。 例如,使用 SQL Server Compact 时,通常建议在应用程序的生存期内保持与数据库的独立开放连接,以提高性能。 您可以使用 Connection 属性手动管理此过程。