首页 > 解决方案 > 当动态数据确定连接字符串时,创建 DbContext 的好模式是什么

问题描述

我从另一个 Web api 获取数据集。它可能包含来自不同客户的多条记录。我必须转换这些数据并将它们写入客户的数据库。每个客户都有自己的数据库。客户端数据库的架构完全相同。

我创建了一个 DbContext 工厂,它根据应用程序当前正在处理的客户端创建一个新的 DbContext 实例。

public ClientDbContext CreateClientDbContext(string clientNumber)
{
      var optionsBuilder = new DbContextOptionsBuilder<ClientDbContext>();
      var clientConnection = string.Format(_configuration.GetConnectionString("clientConnection"), clientNumber);
      optionsBuilder.UseSqlServer(clientConnection);

      clientDbContext clientDbContext = new ClientDbContext(optionsBuilder.Options);

      return clientDbContext;
}

我这样使用工厂:

foreach (var case in caseList)
{
    var clientDbContext = await _clientDbContextFactory.CreateClientDbContext(case.ClientNumber);
    _clientRepository = new ClientRepository(clientDbContext);
    var updatedCase = /// transform case here
    await _clientRepository.CreateCases(updatedCase);
}

是否有这样做的最佳原因?有可能几行数据会有同一个客户端,所以我想重用同一个ClientDbContext。

标签: c#multi-tenantef-core-2.2

解决方案


您可以将用于创建的逻辑移动ClientContext到另一个负责的类中(根据 SOLID 原则),例如并为每个客户DbContextFactory存储 created 。DbContext像这样:

public class DbContextFactory
{
    private readonly IConfiguration _configuration;
    private readonly Dictionary<string, ClientDbContext> _clientContexts = new Dictionary<string, ClientDbContext>();

    public DbContextFactory(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public ClientDbContext GetOrCreateClientContext(string clientNumber)
    {
        // if you have context already created - return it
        if (_clientContexts.ContainsKey(clientNumber))
            return _clientContexts[clientNumber];

        var optionsBuilder = new DbContextOptionsBuilder<ClientDbContext>();
        var clientConnection = string.Format(_configuration.GetConnectionString("clientConnection"), clientNumber);
        optionsBuilder.UseSqlServer(clientConnection);

        var clientDbContext = new ClientDbContext(optionsBuilder.Options);
        _clientContexts[clientNumber] = clientDbContext;

        return clientDbContext;
    }
}

然后在您的工作人员类中,您可以将数据分组ClientNumber,为每个客户端创建(或已经创建)DbContext和存储库,然后进行数据更新。

public class Worker
{
    private readonly DbContextFactory _factory;

    public Worker(DbContextFactory factory)
    {
        _factory = factory;
    }

    public async Task DoWorkAsync()
    {
        // group by ClientNumber
        var groupedCases = caseList.GroupBy(x => x.ClientNumber);

        foreach (var groupedCase in groupedCases)
        {
            // For each client create context and repository
            var clientContext = _factory.GetOrCreateClientContext(groupedCase.Key);
            var clientRepository = new ClientRepository(clientContext);

            foreach (var @case in groupedCases)
            {
                var updatedCase = // transform case here
                await clientRepository.CreateCases(updatedCase);
            }
        }
    }
}

您可以使用依赖注入,也可以像这样创建这些类:

var factory = new DbContextFactory(yourConfiguration);
var worker = new Worker(factory);
await worker.DoWorkAsync();

推荐阅读