DbContext生存期

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

  工作单元维护受业务交易影响的对象的列表,并协调更改的注销和并发问题的解决。

在将数据移入和移出数据库时,重要的是要跟踪所做的更改。否则,该数据将不会被写回到数据库中。同样,您必须插入创建的新对象并删除所有删除的对象。

您可以随着对象模型的每次更改来更改数据库,但是这可能导致许多非常小的数据库调用,这最终会非常缓慢此外,它要求您为整个交互打开一个事务,如果您的业务事务跨越多个请求,则这是不切实际的。如果您需要跟踪已读取的对象,从而避免不一致的读取,则情况甚至更糟。

工作单元会跟踪您在业务交易过程中可能影响数据库的所有操作。完成后,它会计算出由于工作而需要更改数据库的所有工作。英文原文请参考:EAA的P

  EF Core的典型工作单元包括(重点理解这段,有助于我们对EF Core工作原理的理解):

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

  重要知识点:

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

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

  这使得上下文生存期与请求的生存期相关。

  例如:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    
    services.AddDbContext<ApplicationDbContext>(
        options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
}

  依赖关系注入容器)中的作用域服务。 

  options => options.UseSqlServer上下文配置为使用 SQL Server 数据库提供程序,
  "name=ConnectionStrings:DefaultConnection"表示在 ConfigureServices 中的何处调用 AddDbContext 通常不重要。

  例如:

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

  例如:

1 public class MyController
2 {
3     private readonly ApplicationDbContext _context;
4 
5     public MyController(ApplicationDbContext context)
6     {
7         _context = context;
8     }
9 }

  最终结果是为每个请求创建一个 ApplicationDbContext 实例,并传递给控制器,以在请求结束后释放前执行工作单元。

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

例如:

1 public class ApplicationDbContext : DbContext
2 {
3     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
4     {
5         optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test");
6     }
7 }

  例如:

 1 public class ApplicationDbContext : DbContext
 2 {
 3     private readonly string _connectionString;
 4 
 5     public ApplicationDbContext(string connectionString)
 6     {
 7         _connectionString = connectionString;
 8     }
 9 
10     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
11     {
12         optionsBuilder.UseSqlServer(_connectionString);
13     }
14 }

  例如,使用上述为 ASP.NET Core 的 Web 应用定义的 ApplicationDbContext 时:

1 public class ApplicationDbContext : DbContext
2 {
3     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
4         : base(options)
5     {
6     }
7 }

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

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

using var context = new ApplicationDbContext(contextOptions);

使用 DbContext 工厂(例如对于 Blazor)

  例如:

1 public void ConfigureServices(IServiceCollection services)
2 {
3     services.AddDbContextFactory<ApplicationDbContext>(options =>
4         options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test"));
5 }

  此模式与上面传统 ASP.NET Core 部分中使用的模式相同。

1 public class ApplicationDbContext : DbContext
2 {
3     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
4         : base(options)
5     {
6     }
7 }

  例如:

1 private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;
2 
3 public MyController(IDbContextFactory<ApplicationDbContext> contextFactory)
4 {
5     _contextFactory = contextFactory;
6 }

  例如:

1 public void DoSomething()
2 {
3     using (var context = _contextFactory.CreateDbContext())
4     {
5         // ...
6     }
7 }

  请注意,以这种方式创建的 DbContext 实例并非由应用程序的服务提供程序进行管理,因此必须由应用程序释放。

DbContextOptions

可以通过三种方式获取此生成器:

  • 在 AddDbContext 和相关方法中
  • 在 OnConfiguring 中
  • 使用 new 显式构造

这意味着即使使用 AddDbContextOnConfiguring 也可用于执行其他配置。

 

配置数据库提供程序

  例如,若要使用 SQL Server 数据库提供程序:

1 public class ApplicationDbContext : DbContext
2 {
3     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
4     {
5         optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test");
6     }
7 }

  这意味着必须先安装数据库提供程序 NuGet 包,然后才能使用扩展方法。

如果编译器指示找不到方法,请确保已安装提供程序的 NuGet 包,并且你在代码中已有 using Microsoft.EntityFrameworkCore;

  下表包含常见数据库提供程序的示例:

数据库系统

配置示例

NuGet 程序包
SQL Server 或 Azure SQL .UseSqlServer(connectionString) Microsoft.EntityFrameworkCore.SqlServer
Azure Cosmos DB .UseCosmos(connectionString, databaseName) Microsoft.EntityFrameworkCore.Cosmos
SQLite .UseSqlite(connectionString) Microsoft.EntityFrameworkCore.Sqlite
EF Core 内存中数据库 .UseInMemoryDatabase(databaseName) Microsoft.EntityFrameworkCore.InMemory
PostgreSQL* .UseNpgsql(connectionString) Npgsql.EntityFrameworkCore.PostgreSQL
MySQL/MariaDB* .UseMySql((connectionString) Pomelo.EntityFrameworkCore.MySql
Oracle* .UseOracle(connectionString) Oracle.EntityFrameworkCore

避免 DbContext 线程处理问题

因此,始终立即 await 异步调用,或对并行执行的操作使用单独的 DbContext 实例。

  当 EF Core 检测到尝试同时使用 DbContext 实例的情况时,你将看到 InvalidOperationException

 

 

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-12-08
  • 2022-12-23
  • 2021-07-30
  • 2022-12-23
  • 2022-12-23
  • 2021-10-21
猜你喜欢
  • 2021-12-14
  • 2022-12-23
  • 2022-12-23
  • 2022-03-05
  • 2021-11-26
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案