实际上我是从
Blazor
和EF Core
开始的。在注册 DbContext
时,我陷入困境。 DbContext
可以用 AddDbContext
或用 AddDbContextFactory
进行注册。但有什么区别呢?
builder.Services.AddDbContext<DataContext>(opt => opt.UseSqlServer("..."));
builder.Services.AddDbContextFactory<DataContext>(opt => opt.UseSqlServer("..."));
从文档中我得到以下信息:
AddDbContext
:
使用依赖注入时使用此方法...
Entity Framework Core 不支持在同一 Microsoft.EntityFrameworkCore.DbContext 实例上运行多个并行操作。这包括异步查询的并行执行以及来自多个线程的任何显式并发使用。
AddDbContextFactory
:
建议对于 Blazor 应用程序以及依赖项注入范围与上下文生命周期不一致的其他情况注册工厂...
为了方便起见,此方法还将上下文类型本身注册为作用域服务。这允许上下文实例直接从依赖项注入范围解析或由工厂创建(视情况而定)。
那么我们可以全局地说,如果程序需要从不同线程访问
DbContext
,或者同时需要使用AddDbContextFactory
注册上下文,因为当它被创建时(例如在控制器中),lifttime就被设置了范围,所以我们每次都会得到一个新的DbContext
?
private readonly DataContext _dbContext;
public BlogController(IDbContextFactory<DataContext> dbFactory)
{
// Will be created as SCOPED DbContext?
_dbContext = dbFactory.CreateDbContext();
}
我还发现了类似的问题here。
AddDbContext
和AddDbContextFactory
内的生命周期是在注册期间设置的。或者我错过了一些东西。
所以我的问题通常是:
AddDbContextFactory
代替 AddDbContext
?DbContext
和 DbContextFactory
之间的寿命差异是多少?我通常应该将 AddDbContext
DbContextFactory
项目吗?在 Blazor
DbContext
是否会产生内存开销?
对于 HTTP 服务器应用程序,我们有请求/响应周期的范围。这是理想的情况,问题已经解决:注入一个 Scoped DbContext。
对于 Blazor Server 应用程序,就像 WinForms 和 WPF 一样,我们没有如此方便的范围。所以我们必须更直接地管理DbContext。
您可以通过 IDisposable 和/或 OwningComponentBase 使用表单(页面)的生命周期,但该生命周期通常太长。
因此负担转移到存储库(和/或服务):它们必须基于每个方法管理 DbContext。这就是 DbContextFactory 的用武之地:您可以简单地注入 Factory,但每个方法如下所示:
scoped
Blazor WebAssembly 应用程序不会直接使用 DbContext,因此上述内容主要适用于 Blazor Server。
在 Blazor 中始终使用 DbContextFactory。但话虽如此,我相信有人会想出一个例外!
DbContextFactory 和 AddDbContext 与 DbContext 的生命周期有何区别?
DbContextFactory 管理其 DBContext 的生命周期。应用“工作单元”原则,生命周期就是工作单元的生命周期。如果您将上下文直接添加到 DI 容器(例如使用
public async Task<T> GetSomething()
{
using (var ctx = _factory.CreateContext())
{
...
}
}
),那么它会在 DI 容器的生命周期内存在。
我通常应该在 Blazor 项目中使用 DbContextFactory 吗?上面已经回答了
在作用域生命周期内创建 DbContext 是否会产生内存开销?
当然。内存由未处置的对象使用。作用域 DbContext 的生命周期与 DI 容器的生命周期相同。在容器本身被销毁之前,不会对容器内的对象调用 Dispose。这就是为什么您从不使用 Transient DbContexts 的原因。在会话 DI 容器被销毁之前,它们不会被处置。