簡體   English   中英

如何注冊並獲取同類型的多個DbContext?

[英]How to register and get multiple DbContexts of the same type?

因此,想象一下您想要訪問不同環境或服務器(開發、測試、預生產等)上的多個 dbContext,並使用來自所有這些不同數據庫的數據來計算一些東西。 我將如何注冊多個相同類型的 dbContexts ( MonitoringDbContext ) 並區分它們?

這就是我卡住的地方

var envDbContextDetails = configuration.GetSection("EnvironmentConnectionStrings").Get<EnvironmentConnectionStringsModel>();

var nonRegisteredDbContexts = envDbContextDetails.DbConnectionStrings.Where(x => x.Environment != envDbContextDetails.CurrentDbEnvironment).ToList();            

nonRegisteredDbContexts.ForEach(x => services.AddDbContext<MonitoringDbContext>(options => options.UseSqlServer(x.ConnectionString)));

所以我正在注冊多個MonitoringDbContext上下文,現在怎么辦? 我的想法是解決、拉取它們並將它們添加到Dictionary<string, MonitoringDbContext>中,其中鍵是環境名稱(Dev、Test 等),並從DbContextFactory使用它們,我將 select 我需要的那個,或者使用所有它們在一個循環中,這取決於我需要計算的內容。 但我不知道如何在注冊后獲取 dbContexts,以及如何區分它們。

通常應用程序應該與環境無關,不同的環境只是同一應用程序的不同實例,但顯然不是你的情況。

您可以擁有MonitoringDbContext的子類,它通過構造函數傳遞要使用的連接字符串。 這樣您就可以以一種更具聲明性的方式為每個環境創建一個實例。

如果你沒有在編譯時可以知道的固定數量的環境,你將不得不自己實現某種工廠。 這樣的結構將為您擁有的每個環境保存或返回一個實例。 請注意,您必須將該工廠注入到您的類中,而不是直接注入MonitoringDbContext

您可以在服務集合中注冊一個服務的多個實例,並通過解析IEnumerable<T>獲取所有實例,其中 T 是您的服務類型。

知道這一點后,您應該檢查庫的代碼並檢查服務注冊是否在IServiceCollection中進行了簡單的Add EF Core 使用 TryAddX,因此只有您的第一次注冊包含在服務集合中。 所以我們要自定義注冊。

您可以像這樣創建一個包裝器:

public class EnvWrapper<T>
{
    public string Env { get; }
    public T Value { get; }

    public EnvWrapper(string env, T value)
    {
        Env = env;
        Value = value;
    }
}

然后注冊 EF Core 需要運行的基礎服務:

services.AddEntityFrameworkSqlServer();

然后對於每個環境,使用 DbContext 的實例注冊一個 EnvWrapper:

var connectionStringsByEnv = new Dictionary<string, string>
{
    ["dev"] = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=tests;Integrated Security=True;",
    ["prd"] = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=tests;Integrated Security=True;"
};

var services = new ServiceCollection();
services.AddEntityFrameworkSqlServer();

foreach (var cs in connectionStringsByEnv)
{
    var dbContextOptions = new DbContextOptionsBuilder<MonitoringDbContext>()
            .UseSqlServer(cs.Value)
            .Options;

    services.AddScoped(_ =>
    {
        return new EnvWrapper<MonitoringDbContext>(cs.Key, new MonitoringDbContext(dbContextOptions));
    });
}

如果需要,您可以解析IEnumerable<Wrapper<MonitoringDbContext>>並迭代結果:

public class MonitoringDbContextStore : IReadOnlyDictionary<string, MonitoringDbContext>
{
    private readonly Dictionary<string, MonitoringDbContext> _contexts;

    public MonitoringDbContextStore(IEnumerable<EnvWrapper<MonitoringDbContext>> contexts)
    {
        _contexts = contexts.ToDictionary(c => c.Env, c => c.Value/*, StringComparer.OrdinalIgnoreCase*/);
    }
}

也許您應該在您的服務集合中注冊MonitoringDbContextStore

如果您想要/需要IDbContextFactory ,您可以添加更多服務:

services.AddSingleton<IDbContextFactorySource<MonitoringDbContext>, DbContextFactorySource<MonitoringDbContext>>();

每個環境:

services.AddScoped(sp =>
{
    var factorySource = sp.GetRequiredService<IDbContextFactorySource<MonitoringDbContext>>();
    return new EnvWrapper<IDbContextFactory<MonitoringDbContext>>(cs.Key, new DbContextFactory<MonitoringDbContext>(sp, dbContextOptions, factorySource));
});

同樣,您可以解析類型為IEnumerable<EnvWrapper<IDbContextFactory<MonitoringDbContext>>>的 EnvWrapper 集合。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM