C# 实体框架核心中的数据库独立性
我有一个使用postgres的简单WPF/EF Core 2.2.4应用程序。C# 实体框架核心中的数据库独立性,c#,entity-framework-core,entity-framework-core-2.2,C#,Entity Framework Core,Entity Framework Core 2.2,我有一个使用postgres的简单WPF/EF Core 2.2.4应用程序。 我正在分析在SQL Server上迁移它的可能策略 在非ORM应用程序中,通过提供一种动态加载数据库驱动程序的方法(考虑JDBC模型),将特定于数据库的对连接字符串的引用限制在一起是很常见的。在该模型中,您必须解决编写跨数据库工作的SQL的问题 在这里,SQL编写的问题,实际上是主要的问题,从一开始就得到了解决。因此,我发现我们以助手方法的形式重新引入数据库依赖性是非常矛盾的 我的第一个问题是关于DbContext的
我正在分析在SQL Server上迁移它的可能策略 在非ORM应用程序中,通过提供一种动态加载数据库驱动程序的方法(考虑JDBC模型),将特定于数据库的对连接字符串的引用限制在一起是很常见的。在该模型中,您必须解决编写跨数据库工作的SQL的问题 在这里,SQL编写的问题,实际上是主要的问题,从一开始就得到了解决。因此,我发现我们以助手方法的形式重新引入数据库依赖性是非常矛盾的 我的第一个问题是关于DbContext的。OnConfigurang接收用于传递连接字符串的DbContextOptionsBuilder。 但是为了传递连接字符串,需要使用数据库提供程序作为扩展方法提供的特定于数据库的方法。 这是下面示例中的
选项builder.UseNpgsql(connstr)
。
我应该如何在独立于数据库的应用程序中解决这个问题
class MyDbContext: DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
string connstr =
ConfigurationManager
.ConnectionStrings["MYAPP_PROD"].ConnectionString;
optionsBuilder.UseNpgsql(connstr);
}
}
第二个问题是:如何以动态方式加载整个数据库包,以便能够对其进行配置,而不是对其进行编码?
实际上,我使用NuGet获取包:
Npgsql.EntityFrameworkCore.PostgreSQL
说我想使用:
Microsoft.EntityFrameworkCore.SqlServer
如何做到这一点?使用策略模式根据外部配置注册相关数据库提供程序
interface IDbProvider {
bool AppliesTo(string providerName);
DbContextOptions<T> LoadProvider<T>();
}
接口提供程序{
bool AppliesTo(字符串提供程序名);
DbContextOptions加载提供程序();
}
公共类PostgresSqlProvider:IDbProvider{
公共bool AppliesTo(字符串提供程序名){
返回providerName.Equals(“Postgres”);
}
公共DbContextOptions加载提供程序(){
//加载提供程序。
}
}
var providers=new[]{
新的PostgresSqlProvider()
};
var selectedDbProvider=“”//从用户输入/配置加载
var selectedProvider=providers.SingleOrDefault(x=>x.AppliesTo(selectedDbProvider));
if(selectedProvider==null){
抛出新的NotSupportedException($“不支持数据库提供程序{selectedDbProvider}”);
}
var options=selectedProvider.LoadProvider();
使用策略模式根据外部配置注册相关数据库提供程序
interface IDbProvider {
bool AppliesTo(string providerName);
DbContextOptions<T> LoadProvider<T>();
}
接口提供程序{
bool AppliesTo(字符串提供程序名);
DbContextOptions加载提供程序();
}
公共类PostgresSqlProvider:IDbProvider{
公共bool AppliesTo(字符串提供程序名){
返回providerName.Equals(“Postgres”);
}
公共DbContextOptions加载提供程序(){
//加载提供程序。
}
}
var providers=new[]{
新的PostgresSqlProvider()
};
var selectedDbProvider=“”//从用户输入/配置加载
var selectedProvider=providers.SingleOrDefault(x=>x.AppliesTo(selectedDbProvider));
if(selectedProvider==null){
抛出新的NotSupportedException($“不支持数据库提供程序{selectedDbProvider}”);
}
var options=selectedProvider.LoadProvider();
EF Core已经涵盖了该场景。应使用接受生成器操作的任何方法在中配置提供程序
在最简单的情况下(最脏?),您可以根据来自配置系统本身的标志或值选择提供程序,例如:
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 connString=Configuration.GetConnectionString("SchoolContext");
var provider=Configuration.GetSection("MyDbConfig").GetValue<ProviderEnum>("Provider");
services.ConfigureContexts(provider,connString);
var connString=Configuration.GetConnectionString(“学校上下文”);
var provider=Configuration.GetSection(“MyDbConfig”).GetValue(“provider”);
services.ConfigureContexts(提供程序、连接字符串);
建筑工人拣选工
构建器、配置模式允许许多可以处理复杂场景的变体。例如,我们可以提前选择一个生成器方法:
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);
}
}
var efBuilder=SelectBuilder(provider,connString);
AddDbContext(efBuilder);
...
操作SelectBuilder(ProviderEnum提供程序,字符串连接字符串)
{
交换机(提供程序)
{
案例ProviderEnum.SqlServer:
返回ConfigureSql;
案例提供者编号。Postgres:
返回配置Postgres;
}
无效配置SQLServer(DbContextOptionsBuilder选项)
{
options.UseSqlServer(connString);
}
无效配置Postgres(DbContextOptionsBuilder选项)
{
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);
}
}
Action SelectBuilder(ProviderEnum提供程序,字符串连接字符串)
{
返回提供程序开关(提供程序){
ProviderEnum.SqlServer=>ConfigureSql,
ProviderEnum.Postgres=>ConfigurePostgres
};
无效配置SQLServer(DbContextOptionsBuilder选项)
{
options.UseSqlServer(connString);
}
无效配置Postgres(DbContextOptionsBuilder选项)
{
options.UseNpgSql(connString);
}
}
具体配置类
另一种可能是创建强类型配置类,并让它向生成器提供:
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);
}
}
}
类MyDbConfig
{
公共ProviderEnum提供程序{get;set;}
....
公共操作SelectBuilder(字符串连接字符串)
{
返回提供程序开关(提供程序){
ProviderEnum.SqlServer=>ConfigureSql,
ProviderEnum.Postgres=>ConfigurePostgres
};
无效配置SQLServer(DbContextOptionsBuilder选项)
{
options.UseSqlServer(connString);
}
无效配置Postgres(DbContextOptionsBuilder选项)
{
options.UseNpgSql(connString);
}
}
}
并使用它:
var dbConfig=Configuration.Get<MyDbConfig>("MyDbConfig");
var efBuilder=dbCongig.SelectBuilder(connString);
services.AddDbContext<SchoolContext>(efBuilder);
var dbConfig=Configuration.Get(“MyDbConfig”);
var efBuilder=dbCongig.SelectBuilder(connString);
AddDbContext(efBuilder);
EF Core已经涵盖了该场景。应使用接受生成器操作的任何方法在中配置提供程序
在最简单的情况下(最脏?),可以根据标志或值选择提供程序
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);
}
}
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);