使用Npgsql初始化多DbContext导致EF迁移失败的问题
解决Npgsql DataSource多DbContext迁移时的已释放对象错误
问题根源
迁移工具的服务生命周期与应用运行时不同,若NpgsqlDataSource未以单例模式注册,会在迁移过程中被提前释放,触发ObjectDisposedException。直接传连接字符串时EF会自动管理连接源,因此迁移正常,但不符合Npgsql 8.x的最佳实践。
正确实现步骤
1. 单例注册NpgsqlDataSource
根据两个DbContext对应的数据库,注册全局复用的DataSource实例:
// Program.cs var builder = WebApplication.CreateBuilder(args); // 注册ApplicationDb对应的DataSource(默认实例) builder.Services.AddNpgsqlDataSource(builder.Configuration.GetConnectionString("ApplicationDb")); // 注册OtherDb对应的DataSource(命名实例,区分不同库) builder.Services.AddNpgsqlDataSource( builder.Configuration.GetConnectionString("OtherDb"), name: "OtherDbDataSource");
2. 配置DbContext注入对应DataSource
为每个DbContext配置时,从服务容器中获取已注册的DataSource:
// 配置ApplicationDbContext builder.Services.AddDbContext<ApplicationDbContext>((sp, options) => { var dataSource = sp.GetRequiredService<NpgsqlDataSource>(); options.UseNpgsql(dataSource); }); // 配置OtherDbContext(使用命名DataSource) builder.Services.AddDbContext<OtherDbContext>((sp, options) => { var dataSource = sp.GetRequiredService<NpgsqlDataSource>("OtherDbDataSource"); options.UseNpgsql(dataSource); });
3. (可选)添加设计时工厂确保迁移兼容性
若迁移工具仍报错,为DbContext添加设计时工厂,手动创建DataSource避免服务容器的生命周期问题:
public class ApplicationDbContextDesignTimeFactory : IDesignTimeDbContextFactory<ApplicationDbContext> { public ApplicationDbContext CreateDbContext(string[] args) { var config = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .Build(); var dataSource = new NpgsqlDataSourceBuilder(config.GetConnectionString("ApplicationDb")) .Build(); var options = new DbContextOptionsBuilder<ApplicationDbContext>() .UseNpgsql(dataSource) .Options; return new ApplicationDbContext(options); } }
关键注意事项
NpgsqlDataSource是线程安全的连接池管理对象,必须以Singleton生命周期注册,避免重复创建和过早释放。- 多DbContext对应不同数据库时,需用命名DataSource区分,避免注入混淆。
内容的提问来源于stack exchange,提问作者Rob Quincey
相关产品推荐
相关产品推荐

