Зарегистрируйте и внедрите несколько AppDbContext (с одинаковыми полями) для каждой компании в .NET Core

#c# #.net #.net-core #dependency-injection #entity-framework-core

Вопрос:

У меня есть база данных baseDb и BaseDbContext, такие как:

 public class BaseDbContext : DbContext, IBaseDbContext {  public DbSetlt;BaseCompanygt; BaseCompanies { get; set; }  public DbSetlt;BaseUsergt; BaseUsers { get; set; }}  

В нем есть только компании и их собственные строки подключения к базе данных, поэтому, когда какой-либо пользователь запрашивает что-то, я получаю это из его базы данных на основе его идентификатора компании.

Я добавил baseDbContext при запуске.cs следующим образом:

 services.AddDbContextlt;BaseDbContextgt;((serviceProvider, optionsBuilder) =gt; {  optionsBuilder.UseNpgsql(connectionString,  b =gt; b.MigrationsAssembly(typeof(BaseDbContext).Assembly.FullName));  optionsBuilder.UseApplicationServiceProvider(serviceProvider);  });  

Теперь, когда сервер запускается, мне нужно просмотреть записи компаний из baseDb и открыть соединение, а затем внедрить его (службы.AddDbContext), как я могу это сделать??

То, что я сделал в последнее время (это не точно), я создал словарь, в котором содержатся строки подключения и контексты applicationdb, и я установил их после открытия соединения с baseDb, как:

 public static Dictionarylt;string, ApplicationDbContextgt; CompaniesDbContext { get; set; } //* connectionString : DbContext   private static async Tasklt;ApplicationDbContextgt; ConnectToDb(string ConnectionString) {  var optionsBuilder = new DbContextOptionsBuilderlt;ApplicationDbContextgt;();  optionsBuilder.UseNpgsql(ConnectionString,  b =gt; b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName));  var context = new ApplicationDbContext(optionsBuilder.Options, _currentUserService, _dateTime);  context.Database.Migrate();  await new ApplicationDbContextSeed(context).SeedRegistryAsync();  return context;  }  

Я использую эту статическую переменную при каждом запросе, чтобы заставить компанию DbContext использовать ее.

Вопрос в следующем: Как зарегистрировать несколько DbContext (в моем случае это ApplicationDbContext), чтобы, когда пользователь запрашивает что-то, я получал это из базы данных его компании.

Статический способ выдает ошибку, когда 2 запроса выполняются одновременно, потому что ApplicationDbContext не вводится при внедрении зависимостей в Startup.cs.

 ystem.InvalidOperationException: A second operation was started on this context before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.  

Ответ №1:

Для этого:

  • сохраните ключ компании в пользовательском токене.
  • в вашем startup.cs добавлении вы используете DbContext
 services.TryAddSingletonlt;IHttpContextAccessor, HttpContextAccessorgt;( ); services.AddDbContextlt;ApplicationDbContextgt;( );  
  • В вашем ApplicationDbContext.cs
  public ApplicationDbContext(DbContextOptionslt;ApplicationDbContextgt; options, HttpContextAccessor httpContextAccessor)  : base(options) {  _httpContext = httpContextAccessor?.HttpContext; }  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {  if (optionsBuilder.IsConfigured) {  return;  }   var key = _httpContext?.User.Claims  .Where(c =gt; c.Type == "company")  .Select(c =gt; c.Value)  .SingleOrDefault();   var conString = new PrivateStorageService().GetConnectionString(key);  optionsBuilder.UseNpgsql(conString); }   

а затем вызовите свой ApplicationDbContext из любого класса из конструктора. и вы должны получить контекст для вошедшего в систему пользователя

Ответ №2:

Вместо сохранения статического списка ApplicationDbContext я сохранил только DbContextOptionsBuilder, и при получении контекста я создал новый экземпляр класса ApplicationDbContext, передав соответствующий OptionBuilder, и он работает.