Как иметь несколько DbContext одного типа?

#c# #asp.net-core #entity-framework-core

#c# #asp.net-core #entity-framework-core

Вопрос:

Я хочу сделать некоторые отчеты в ASP.NET Основной веб-сайт, который считывает данные из нескольких баз данных, используя одну и ту же схему.

В Startup.cs мне нужно иметь что-то вроде:

 public void ConfigureServices(IServiceCollection services)
{

// Some other stuff here.

services.AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.GetConnectionString("FirstConnectionString")));
services.AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SecondConnectionString")));

}
  

Но теперь DbContext имеют один и тот же тип и не имеют имени, так как же мне выбрать тот, который я хочу использовать в контроллере?

 public class HomeController : Controller
{

    private readonly MyContext context;

    public HomeController(MyContext context)
    {
        // Is that the one with FirstConnectionString or SecondConnectionString?
        // How do I choose?
        this.context = context;
    }

}
  

Редактировать:

Возможно, я чего-то не понимаю, но в MyContext у меня есть:

 public class MyContext : DbContext
{

    public MyContext(DbContextOptions<MyContext> options) : base(options)
    {
    }

    // Some more code here.

}
  

Тогда в MyContext1 у меня есть:

 public class MyContext1 : MyContext
{

    // base in now MyContext and not DbContext !!!
    // Error with: public MyContext1(DbContextOptions<MyContext1> options) : base(options)
    public MyContext1(DbContextOptions<MyContext> options) : base(options)
    {
    }

}
  

Если я добавляю 2 производных типа при запуске и запускаю его, происходит сбой и выдается следующее сообщение об ошибке:

 InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[MyContext]' while attempting to activate 'MyContext1'.
  

Если я также добавлю базовый тип при запуске (таким образом, 3 типа с 3 разными строками подключения), то все 3 типа будут использовать строку подключения базового типа.

Комментарии:

1. Вам придется использовать две контекстные модели. Если схема в точности одинакова, просто создайте 3 класса и сделайте так, чтобы два контекста наследовали класс schema (исходный класс context).

2. Добавил некоторые дополнительные детали к моему ответу, чтобы учесть ваши правки 🙂

Ответ №1:

Почему бы просто не создать два DbContexts? Теоретически, создание 3, вероятно, чище .. сохраните настроенный вами MyContext, а затем просто создайте Db1Context и Db2Context, которые наследуются от него? означает, что ваша регистрация заканчивается как

 services.AddDbContext<Db1Context>(options => options.UseSqlServer(Configuration.GetConnectionString("FirstConnectionString")));
services.AddDbContext<Db2Context>(options => options.UseSqlServer(Configuration.GetConnectionString("SecondConnectionString")));
  

таким образом, его легко решить, и благодаря наследованию вы избегаете некоторого дублирования кода.. но я не вижу никакой пользы от попыток сохранить 1 dbcontext, который передается в несколько db в одном приложении

Редактировать: Если у вас все еще возникают некоторые проблемы с работой DI, на Github был довольно старый поток, который выглядит так, как будто у кого-то была проблема такого типа, которую они решили, выполнив

 public class EFDbContext : DbContext
    {
        public EFDbContext(DbContextOptions<EFDbContext> options) : base(options) { }
        protected MainDbContext(DbContextOptions options) : base(options) { }
    }

public class DimensionsDbContext : EFDbContext
    {
        public DimensionsDbContext(DbContextOptions<DimensionsDbContext> options) : base(options) { }
    }
  

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

Комментарии:

1. Возможно, я что-то упускаю, но просто DbContextOptions options не компилируется.

2. Очевидно, что это старый вопрос и ответ, но я просто хотел обновить это для людей, которые ищут будущие предложения. Предлагаемая очередь редактирования заполнена, поэтому опубликую здесь: Ошибка с приведенным выше в том, что там написано protected MainDbContext , но это должно быть protected EFDbContext

Ответ №2:

В конце я создаю несколько контекстов в своих контроллерах отчетов. Это не DI-способ, но он работает.

У меня есть что-то вроде следующего кода в конструкторе контроллера:

 var firstOptionsBuilder = new DbContextOptionsBuilder<MyContext>();
firstOptionsBuilder.UseSqlServer("firstConnectionString");
var firstContext = new MyContext(firstOptionsBuilder.Options);