什么时候该用 AddDbContextFactory
而不是 AddDbContext
当你需要在运行时动态创建多个独立的
DbContext实例(比如按租户、按请求参数、或按数据库连接字符串切换),或者需要手动控制上下文生命周期(例如在后台任务中短时使用后立即释放),
AddDbContextFactory是更合适的选择。它不注册
DbContext本身,而是注册一个工厂
IDbContextFactory<tcontext></tcontext>,由你显式调用
CreateDbContext()来获取新实例。
而
AddDbContext是常规做法:它把
DbContext当作服务注册进 DI 容器,默认按作用域(
Scoped)生命周期管理,每次从同一个作用域(如一个 HTTP 请求)内解析出的都是同一个实例——这适合大多数 Web API 或 MVC 场景,但隐含了共享状态风险,且无法按需构造不同配置的上下文。
AddDbContextFactory
的典型使用场景和注意事项
常见于多租户系统、ETL 批处理、或需要并行操作多个数据库的后台服务。它默认注册为
Singleton,工厂本身是线程安全的,但生成的每个
DbContext实例仍是短生存期、不可共享的。 必须手动调用
factory.CreateDbContext(),不能直接注入
MyDbContext生成的
DbContext不参与当前作用域的自动释放,需确保用
using或显式
Dispose()若在 ASP.NET Core 请求处理中混用,容易因忘记释放导致连接泄漏 不支持 EF Core 的变更跟踪器跨实例共享,每个上下文都是完全隔离的
配置方式差异:连接字符串和选项如何传入
AddDbContext通常在注册时通过
options => options.UseSqlServer(...)固定配置;而
AddDbContextFactory支持两种方式: 注册时传入固定配置(同上),所有工厂创建的上下文共用同一套选项 注册时不指定连接字符串,改用
factory.CreateDbContext(new[] { "Server=..." }) 动态传参(需自定义 DbContextOptionsBuilder构建逻辑)
后者更灵活,但需重写
OnConfiguring或提供自定义
IDbContextFactory实现,EF Core 原生工厂不直接支持运行时切换连接字符串——得靠包装一层逻辑。
性能与内存影响:别以为工厂就一定“更轻量”
工厂本身开销小,但每次调用
CreateDbContext()都会新建整个
DbContext实例及其依赖(如
ChangeTracker、
Database等),比复用作用域内已存在的上下文成本更高。如果只是想避免“单个请求里多次注入上下文”,用
AddDbContext+
ServiceLifetime.Scoped更高效;只有明确需要“每个操作独占上下文”时,才值得用工厂。
另外,若误在循环里高频调用
CreateDbContext()却没及时
Dispose(),会快速耗尽数据库连接池——这是最常被忽略的实际问题。
services.AddDbContextFactory<AppDbContext>(options =>
options.UseSqlServer(connectionString)
.EnableSensitiveDataLogging());
工厂注册之后,用的时候得这样:
public class Worker : BackgroundService
{
private readonly IDbContextFactory<AppDbContext> _factory;
public Worker(IDbContextFactory<AppDbContext> factory) => _factory = factory;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await using var context = _factory.CreateDbContext(); // 必须 using
var count = await context.Users.CountAsync(stoppingToken);
}
}
真正难的不是怎么写这行
_factory.CreateDbContext(),而是判断清楚:你到底需不需要这个“每次都新建”的行为——多数时候,你并不需要。
