public sealed class ApplicationDbContext1 : ApplicationDbContextBase
public ApplicationDbContext1(DbContextOptions<ApplicationDbContext1> contextOptions)
: base(contextOptions)
public sealed class ApplicationDbContext2 : ApplicationDbContextBase
public ApplicationDbContext2(DbContextOptions<ApplicationDbContext2> contextOptions)
: base(contextOptions)
请注意,这与直接从 DbContext
继承的模式完全相同。 也就是说,出于此原因,DbContext
构造函数本身将接受非泛型 DbContextOptions
。
旨在同时进行实例化和继承的 DbContext
子类应公开构造函数的两种形式。 例如:
public class ApplicationDbContext : DbContext
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> contextOptions)
: base(contextOptions)
protected ApplicationDbContext(DbContextOptions contextOptions)
: base(contextOptions)
设计时 DbContext 配置
EF Core 设计时工具(如 EF Core迁移)需要能够发现并创建 DbContext
类型的工作实例,以收集有关应用程序的实体类型及其如何映射到数据库架构的详细信息。 只要该工具可以通过与在运行时的配置方式类似的方式轻松地创建 DbContext
,就可以自动执行此过程。
虽然向 DbContext
提供必要配置信息的任何模式都可以在运行时正常运行,但在设计时需要使用 DbContext
的工具只能使用有限数量的模式。 设计时上下文创建中包含更多详细信息。
避免 DbContext 线程处理问题
Entity Framework Core 不支持在同一 DbContext
实例上运行多个并行操作。 这包括异步查询的并行执行以及从多个线程进行的任何显式并发使用。 因此,始终立即 await
异步调用,或对并行执行的操作使用单独的 DbContext
实例。
当 EF Core 检测到尝试同时使用 DbContext
实例的情况时,你将看到 InvalidOperationException
,其中包含类似于以下内容的消息:
在上一个操作完成之前,第二个操作已在此上下文中启动。 这通常是由使用同一个 DbContext 实例的不同线程引起的,但不保证实例成员是线程安全的。
检测不到并发访问时,可能会导致未定义的行为、应用程序崩溃和数据损坏。
一些常见错误可能会无意中导致并发访问同一 DbContext
实例:
异步操作缺陷
使用异步方法,EF Core 可以启动以非阻挡式访问数据库的操作。 但是,如果调用方不等待其中一个方法完成,而是继续对 DbContext
执行其他操作,则 DbContext
的状态可能会(并且很可能会)损坏。
始终立即等待 EF Core 异步方法。
通过依赖关系注入隐式共享 DbContext 实例
默认情况下 AddDbContext
扩展方法使用DbContext
范围内生存期来注册 类型。
这样可以避免在大多数 ASP.NET Core 应用程序中出现并发访问问题,因为在给定时间内只有一个线程在执行每个客户端请求,并且每个请求都有单独的依赖关系注入范围(因此有单独的 DbContext
实例)。 对于 Blazor Server 托管模型,一个逻辑请求用来维护 Blazor 用户线路,因此,如果使用默认注入范围,则每个用户线路只能提供一个范围内的 DbContext 实例。
任何并行显式执行多个线程的代码都应确保 DbContext
实例不会同时访问。
使用依赖关系注入可以通过以下方式实现:将上下文注册为范围内,并为每个线程创建范围(使用 IServiceScopeFactory
),或将 DbContext
注册为暂时性(使用采用 ServiceLifetime
参数的 AddDbContext
的重载)。
进一步阅读
请阅读依赖关系注入以了解有关使用 DI 的详细信息。
请阅读测试以了解详细信息。