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