您可以通过创建工厂类来实现您的目标。
假设您有一个接受的 DbContext 类DbContextOptions<T>
:
class AppDbContext: DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
}
我们可以复制 EF Core 如何在工厂内部注册和实例化 DbContext 并动态生成和提供选项。
我ConnectionConfiguration
用作连接信息的通用占位符。您可能更愿意将此信息存储在Customer
实体中。
record ConnectionConfiguration(string Provider, string ConnectionString);
class DynamicDbContextFactory<TContext> where TContext: DbContext
{
private readonly IServiceProvider _serviceProvider;
private Func<IServiceProvider, DbContextOptions<TContext>, TContext> _factory;
public DynamicDbContextFactory(IServiceProvider serviceProvider, IDbContextFactorySource<TContext> factorySource)
{
_serviceProvider = serviceProvider;
_factory = factorySource.Factory;
}
public Task<TContext> CreateDbContextAsync(ConnectionConfiguration connection)
{
var builder = new DbContextOptionsBuilder<TContext>()
.UseApplicationServiceProvider(_serviceProvider);
builder = connection.Provider switch
{
"sqlite" => builder.UseSqlite(connection.ConnectionString),
"npgsql" => builder.UseNpgsql(connection.ConnectionString),
_ => throw new InvalidOperationException("No such provider")
};
var db = _factory(_serviceProvider, builder.Options);
return Task.FromResult(db);
}
}
这里我使用IDbContextFactorySource
的是 ,它是一个没有支持保证的内部类型,并在编译期间引发警告。但是您可以简单地复制其源代码以找到合适的构造函数并创建工厂方法。
然后我们需要注册几个服务:
services.AddDbContext<AppDbContext>(db => db.UseInMemoryDatabase(nameof(AppDbContext)));
services.AddSingleton<IDbContextFactorySource<AppDbContext>, DbContextFactorySource<AppDbContext>>();
services.AddSingleton(typeof(DynamicDbContextFactory<>)); // register as open generic type and let DI close the type during resolution
然后我们可以从服务提供者那里解析这个工厂并动态创建一个实例:
class CustomerService
{
private DynamicDbContextFactory<AppDbContext> _contextFactory;
public CustomerService(DynamicDbContextFactory<AppDbContext> contextFactory)
{
_contextFactory = contextFactory;
}
public async Task SaveThingsAsync()
{
// fetch connection info from somewhere
var conn = new ConnectionConfiguration(Provider: "sqlite", ConnectionString: "Data Source=:memory:");
await using var db = await _contextFactory.CreateDbContextAsync(conn);
await db.Set<Sales>().AddAsync(new Sale( /*...*/));
await db.SaveChangesAsync();
}
}
注意:由于您是创建 DbContext 的人,因此您还应该在完成后处理它(使用using
语句或通过实现IDisposable
)。