EF中的上下文(DbContext)简介

 

DbContext是实体类和数据库之间的桥梁,DbContext主要负责与数据交互,主要作用:

1、DbContext包含所有的实体映射到数据库表的实体集(DbSet < TEntity >)。

2、DbContext 将LINQ-to-Entities查询转换为SQL查询并将其发送到数据库。

3、更改跟踪: 它跟踪每个实体从数据库中查询出来后发生的修改变化。

4、持久化数据: 它也基于实体状态执行插入、更新和删除操作到数据库中。

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

DbSet<TEntity> 类

DbContext中的DbSet

DbSet表示上下文中指定类型的所有实体的集合或可从数据库中查询的指定类型的所有实体的集合。

DbSet<TEntity>可用于查询和保存的实例 TEntity 。 针对的 LINQ 查询 DbSet<TEntity> 将转换为针对数据库的查询。

针对的 LINQ 查询结果 DbSet<TEntity> 将包含从数据库返回的结果,并且可能不会反映在尚未保存到数据库的上下文中所做的更改。 例如,结果将不包含新添加的实体,可能仍包含标记为要删除的实体。

根据所使用的数据库,可以在内存中计算 LINQ 查询的某些部分,而不是将其 DbSet<TEntity> 转换为数据库查询。

DbSet<TEntity> 对象通常从 DbSet<TEntity> 派生的属性 DbContext 或从 Set<TEntity>() 方法获取。

DbContext 生存期

DbContext 的生存期从创建实例时开始,并在释放实例时结束。 DbContext 实例旨在用于单个工作单元。 这意味着 DbContext 实例的生存期通常很短。

使用 Entity Framework Core (EF Core) 时的典型工作单元包括:

  • 创建 DbContext 实例
  • 根据上下文跟踪实体实例。 实体将在以下情况下被跟踪
  • 根据需要对所跟踪的实体进行更改以实现业务规则
  • 调用 SaveChanges 或 SaveChangesAsync。 EF Core 检测所做的更改,并将这些更改写入数据库。
  • 释放 DbContext 实例

 重要

  • 使用后释放 DbContext 非常重要。 这可确保释放所有非托管资源,并注销任何事件或其他挂钩,以防止在实例保持引用时出现内存泄漏。
  • DbContext 不是线程安全的。 不要在线程之间共享上下文。 请确保在继续使用上下文实例之前,等待所有异步调用。
  • EF Core 代码引发的 InvalidOperationException 可以使上下文进入不可恢复的状态。 此类异常指示程序错误,并且不旨在从其中恢复

ASP.NET Core 依赖关系注入中的 DbContext

在许多 Web 应用程序中,每个 HTTP 请求都对应于单个工作单元。 这使得上下文生存期与请求的生存期相关,成为 Web 应用程序的一个良好默认值。

使用依赖关系注入配置 ASP.NET Core 应用程序。 可以使用 Startup.cs 的 ConfigureServices 方法中的 AddDbContext 将 EF Core 添加到此配置。 例如:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddDbContext<ApplicationDbContext>(
        options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
}

此示例将名为 ApplicationDbContext 的 DbContext 子类注册为 ASP.NET Core 应用程序服务提供程序(也称为 依赖关系注入容器)中的作用域服务。 上下文配置为使用 SQL Server 数据库提供程序,并将从 ASP.NET Core 配置读取连接字符串。 在 ConfigureServices 中的何处调用 AddDbContext 通常不重要。

ApplicationDbContext 类必须公开具有 DbContextOptions<ApplicationDbContext> 参数的公共构造函数。 这是将 AddDbContext 的上下文配置传递到 DbContext 的方式。 例如:

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

  然后,ApplicationDbContext 可以通过构造函数注入在 ASP.NET Core 控制器或其他服务中使用。 例如:

public class ApplicationDbContext : DbContext
{
    private readonly string _connectionString;

    public ApplicationDbContext(string connectionString)
    {
        _connectionString = connectionString;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(_connectionString);
    }
}

使用“new”的简单的 DbContext 初始化

  可以按照常规的 .NET 方式构造 DbContext 实例,例如,使用 C# 中的 new。 可以通过重写 OnConfiguring 方法或通过将选项传递给构造函数来执行配置。 例如:

public class ApplicationDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test");
    }
}

通过此模式,还可以轻松地通过 DbContext 构造函数传递配置(如连接字符串)。 例如:

public class ApplicationDbContext : DbContext
{
    private readonly string _connectionString;

    public ApplicationDbContext(string connectionString)
    {
        _connectionString = connectionString;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(_connectionString);
    }
}

灵活的DbContext 初始化

或者,可以使用 DbContextOptionsBuilder 创建 DbContextOptions 对象,然后将该对象传递到 DbContext 构造函数。 这使得为依赖关系注入配置的 DbContext 也能显式构造。 例如,使用上述为 ASP.NET Core 的 Web 应用定义的 ApplicationDbContext 时:

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

可以创建 DbContextOptions,并可以显式调用构造函数:

var contextOptions = new DbContextOptionsBuilder<ApplicationDbContext>()
    .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test")
    .Options;

using var context = new ApplicationDbContext(contextOptions);