c# AddDbContextFactory 和 AddDbContext 的区别

来源:这里教程网 时间:2026-02-21 17:36:23 作者:

什么时候该用
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()
,而是判断清楚:你到底需不需要这个“每次都新建”的行为——多数时候,你并不需要。

相关推荐

热文推荐