允許最終用戶在運行時切換Entity Framework提供程序

asp.net-core c# entity-framework-core

考慮到我已使用.NET Core Web應用程序配置EF:

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

我也可以下載一個包來支持例如SQLite:

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

我們如何允許用戶在應用安裝上“選擇”提供商?我的意思是 - 例如,在WordPress中,您可以從下拉列表中進行選擇。

這在.NET Core中是否可行?我看到的唯一方法是僅重啟應用程序...

一般承認的答案

下面是一個關於如何實現DbContextFactoryDbContextProxy<T>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;
    }
}

然後你可以選擇正確的提供者w / o硬編碼if/elseswitch塊只是這樣做

// 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類一樣簡單。

有關方法和類似方法的詳細信息,請參見此處此處此處


熱門答案

我認為您可以使用使用您指定的db上下文的存儲庫,並且可以將參數傳遞給上下文構造函數以選擇端點。我不確定這一點,但它可能適合你的情況。

我按照這篇文章的存儲庫模式,我建議閱讀它:)

http://cpratt.co/generic-entity-base-class/



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow