考虑到我已使用.NET Core Web应用程序配置EF:
services.AddDbContext<ApplicationDbContext>(options => options.UsesqlServer(...));
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);