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

时间:2016-11-18 23:32:11

标签: c# asp.net-core entity-framework-core

请考虑我已使用.NET Core Web应用程序配置EF:

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

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

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

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

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

2 个答案:

答案 0 :(得分:3)

以下是有关如何实施DbContextFactoryDbContextProxy<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(); } } } services.AddScopedd<IDbContextFactory, DbContextFactory>(); 将创建正确的提供程序并将其返回。

IDbContextProxy<T>

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

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

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块的正确提供商
PBYTE AddPadding(PBYTE Array, int size)
{
    if (size % 16 != 0)
    {
        size += (16 - size % 16);
        size = ceil(size / 16) * 16;
    }

    BYTE* tmp = new BYTE[size];

    //the magic should happen here

    return tmp;
}

添加新类型的提供程序就像添加依赖项和BYTE in[] = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, 0x25 }; PBYTE tmp = AddPadding(in, sizeof(in)); 类一样简单。

有关此方法和类似方法的详情,请参阅hereherehere

答案 1 :(得分:0)

我认为您可以使用使用您指定的db上下文的存储库,并且可以将参数传递给上下文构造函数以选择端点。我不确定这一点,但它可能适用于你的情况。

我按照这篇文章讨论了存储库模式,我建议你阅读它:)

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