Этот сценарий уже охватывается EF Core. Конфигурирование провайдеров должно быть выполнено в Startup.ConfigureServices , используя любой из AddDbContext методов, которые принимают действие компоновщика.
В самом простом случае (самом грязном?) Выможет выбирать провайдеров на основе флага или значения, полученного из самой системы конфигурации, например:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
var connString=Configuration.GetConnectionString("SchoolContext");
var useSqlServer=Configuration.GetSection("MyDbConfig").GetValue<bool>("UseSqlServer");
services.AddDbContext<SchoolContext>(options =>{
if (useSqlServer)
{
options.UseSqlServer(connString);
}
else
{
options.UseNpgsql(connString);
}
});
}
или
var provider=Configuration.GetSection("MyDbConfig").GetValue<ProviderEnum>("Provider");
services.AddDbContext<SchoolContext>(options =>{
switch (provider)
{
case ProviderEnum.SqlServer:
options.UseSqlServer(connString);
break;
case ProviderEnum.Postgres :
options.UseNpgsql(connString);
break;
...
}
});
Этот флаг также может быть получен из конфигурации, например, изкомандная строка, переменные среды и т. д.
Рефакторинг на .... лоты
Метод расширения
Этот кодможет быть извлечен в метод расширения в IServiceCollection
, аналогично другим контекстам, например:
public static ConfigureContexts(this IServiceCollection services,string connString, string provider)
{
services.AddDbContext<SchoolContext>(options =>{
switch (provider)
{
case ProviderEnum.SqlServer:
options.UseSqlServer(connString);
break;
case ProviderEnum.Postgres :
options.UseNpgsql(connString);
break;
...
}
});
}
и использован:
var connString=Configuration.GetConnectionString("SchoolContext");
var provider=Configuration.GetSection("MyDbConfig").GetValue<ProviderEnum>("Provider");
services.ConfigureContexts(provider,connString);
Выбор сборщика
Конструктор, шаблоны конфигурации допускают множество вариантов, которые могут обрабатывать сложные сценарии. Например, мы можем заранее выбрать метод конструктора:
var efBuilder= SelectBuilder(provider,connString);
services.AddDbContext<SchoolContext>(efBuilder);
...
Action<DbContextOptionsBuilder> SelectBuilder(ProviderEnum provider,string connString)
{
switch (provider)
{
case ProviderEnum.SqlServer:
return ConfigureSql;
case ProviderEnum.Postgres :
return ConfigurePostgres;
}
void ConfigureSqlServer(DbContextOptionsBuilder options)
{
options.UseSqlServer(connString);
}
void ConfigurePostgres(DbContextOptionsBuilder options)
{
options.UseNpgSql(connString);
}
}
В C # 8 это можно уменьшить до:
Action<DbContextOptionsBuilder> SelectBuilder(ProviderEnum provider,string connString)
{
return provider switch (provider) {
ProviderEnum.SqlServer => ConfigureSql,
ProviderEnum.Postgres => ConfigurePostgres
};
void ConfigureSqlServer(DbContextOptionsBuilder options)
{
options.UseSqlServer(connString);
}
void ConfigurePostgres(DbContextOptionsBuilder options)
{
options.UseNpgSql(connString);
}
}
Конкретный класс конфигурации
Еще одна возможность - создать строго типизированный класс конфигурации и it предоставить сборщику:
class MyDbConfig
{
public ProviderEnum Provider {get;set;}
....
public Action<DbContextOptionsBuilder> SelectBuilder(string connString)
{
return provider switch (provider) {
ProviderEnum.SqlServer => ConfigureSql,
ProviderEnum.Postgres => ConfigurePostgres
};
void ConfigureSqlServer(DbContextOptionsBuilder options)
{
options.UseSqlServer(connString);
}
void ConfigurePostgres(DbContextOptionsBuilder options)
{
options.UseNpgSql(connString);
}
}
}
и использовать его:
var dbConfig=Configuration.Get<MyDbConfig>("MyDbConfig");
var efBuilder=dbCongig.SelectBuilder(connString);
services.AddDbContext<SchoolContext>(efBuilder);