c# – 允许最终用户在运行时切换Entity Framework提供程序

考虑到我已使用.NET Core Web应用程序配置EF:
services.AddDbContext<ApplicationDbContext>(options => 
    options.UseSqlServer(...));

我也可以下载一个包来支持例如SQLite:

services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(...));

我们如何允许用户在应用安装上“选择”提供商?我的意思是 – 例如,在WordPress中,您可以从下拉列表中进行选择.

这在.NET Core中是否可行?我看到的唯一方法是仅重启应用程序…

解决方法

这是一个关于如何实现DbContextFactory或DbContextProxy< T>的示例.这将创建正确的提供程序并返回它.
public interface IDbContextFactory
{
    ApplicationContext Create();
}

public class DbContextFactory() : IDbContextFactory,IDisposable
{
    private ApplicationContext context;
    private bool disposing;

    public DbContextFactory()
    {
    }

    public ApplicationContext Create() 
    {
        if(this.context==null) 
        {
            // Get this value from some configuration
            string providerType = ...;
            // and the connection string for the database
            string connectionString = ...;

            var dbContextBuilder = new DbContextOptionsBuilder();
            if(providerType == "MSSQL") 
            {
                dbContextBuilder.UseSqlServer(connectionString);
            }
            else if(providerType == "Sqlite")
            {
                dbContextBuilder.UseSqlite(connectionString);
            }
            else 
            {
                throw new InvalidOperationException("Invalid providerType");
            }

            this.context = new ApplicationContext(dbContextBuilder);
        }

        return this.context;
    }

    public void Dispose(){
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing){
        if (disposing){
            disposing?.Dispose();
        }
    }
}

还要确保如上所示实现一次性模式,以便在工厂处置后立即处理上下文,以防止DbContext在内存中保留的时间超过必要时间并尽快释放非托管资源.

最后将工厂注册为作用域,就像上下文本身一样:

services.AddScopedd<IDbContextFactory,DbContextFactory>();

更先进和通用/可扩展的方法是通过创建IDbContextProxy< T>.使用一些反射来获取正确的构造函数和DbContextOptionsBuilder的类.

也可以创建一个抽象提供者创建的IDbContextBuilder.

public class SqlServerDbContextBuilder IDbContextBuilder
{
    public bool CanHandle(string providerType) => providerType == "SqlServer";

    public T CreateDbContext<T>(connectionString)
    {
        T context = ... // Create the context here

        return context;
    }
}

然后你可以选择没有硬编码if / else或switch块的正确提供者

// Inject "IEnumerable<IDbContextBuilder> builders" via constructor
var providerType = "SqlServer";
var builder = builders.Where(builder => builder.CanHandle(providerType)).First();
var context = builder.CreateDbContext<ApplicationContext>(connectionString);

添加新类型的提供程序就像添加依赖项和XxxDbContextBuilder类一样简单.

有关此方法和类似方法的更多信息,请参见here,herehere.

相关文章

项目中经常遇到CSV文件的读写需求,其中的难点主要是CSV文件...
简介 本文的初衷是希望帮助那些有其它平台视觉算法开发经验的...
这篇文章主要简单记录一下C#项目的dll文件管理方法,以便后期...
在C#中的使用JSON序列化及反序列化时,推荐使用Json.NET——...
事件总线是对发布-订阅模式的一种实现,是一种集中式事件处理...
通用翻译API的HTTPS 地址为https://fanyi-api.baidu.com/api...