#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, и он работает.