Строки соединения Entity Framework Core 1.0

Мы работаем над различными приложениями ASP.NET Core MVC 1.0. У нас есть 4 уровня для каждого из наших приложений:

  • DTO
  • Репозиторий (Entity Framework - первый код)
  • Служба (бизнес-логика)
  • MVC (UI-MVC)

В настоящее время в наших репозиториях, которые обрабатывают все операции с базой данных, мы жестко закодировали строки подключения к базе данных в DbContext следующим образом:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {

    optionsBuilder.UseSqlServer("Data Source=somedatabase.database.windows.net;Initial Catalog=database;Integrated Security=False;User ID=username;Password=password;Connect Timeout=60;Encrypt=True;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False;MultipleActiveResultSets=true");

}

Этот проект находится за пределами проекта MVC как автономный проект ASP.NET Core 1.0. У него также есть пустой файл Program.cs, который, как представляется, требуется для выполнения командных строк кода в базу данных (обновление сетевых сообщений dotnet ef и обновление базы данных dotnet ef).

Причина, по которой у нас есть строка с жестким кодированием в DbConext, заключается в том, что, когда мы используем следующий код, мы получаем ссылку на объект, не установленную в экземпляр для исключения объекта, при выполнении команд dotnet ef.

  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {

    optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["StandardDatabase"].ConnectionString);

  }

Однако, поскольку у нас есть Program.cs, если мы добавим Debug.WriteLine для строки подключения и запустим проект, она вернет правильную строку соединений, и если мы установим строку подключения в файле appsettings.json в пользовательский интерфейс, пользовательский интерфейс также будет успешно подключен.

ВЫПУСК: Вышеупомянутый стек - это то, что мы используем для нескольких "Micro Apps", что означает, что у нас есть несколько проектов, которые подключаются к нескольким базам данных. Мы также хотим использовать строки разработки, Staging и Production.

Если мы используем Connection Connection Connection String, все хорошо для ежедневных операций; однако, когда мы хотим использовать код Entity Frameworks в командных строках базы данных, нам нужно зайти в каждый репозиторий, который мы хотим обновить, и изменить DbContext на строку жесткого кодированного соединения, выполнить команды, а затем вернуть их обратно, когда это будет сделано, что становится довольно хлопотным.

ВОПРОС: Делаем ли мы это неправильно, есть ли предпочтительная практика для создания стека Entity Framework Core 1.0, который позволяет нам не вручную изменять DbContext, а использовать файлы конфигурации по всем направлениям?

Любое направление будет оценено!

Ответ 1

EF Core предназначен для настройки посредством инъекции зависимостей. Инъекционная инъекция сохраняет чистоту DbContext и не зависит от деталей реализации среды.

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

Чтобы DbContext не зависел от данных о состоянии окружающей среды, создайте конструктор, который принимает параметр DbContextOptions и вызывает конструктор базового класса.

public class MyContext : DbContext
{
    public MyContext(DbContextOptions options) :
        base(options)
    {
    }
}

Сделайте это вместо переопределения OnConfiguring. Затем инициализируйте его в Startup.cs вашего хост-приложения. То, что принадлежит знанию файла конфигурации.

public class Startup
{
    private IConfigurationRoot _configuration;

    public Startup(IHostingEnvironment env)
    {
        _configuration = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json")
            .Build();
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IConfigurationRoot>(_configuration);

        services.AddDbContext<MyContext>(options => options
            .UseSqlServer(_configuration.GetConnectionString("MyContext")));
    }
}

Теперь вы можете использовать свой DbContext где угодно.

Ответ 2

ОТВЕТ: Я делал это намного сложнее, чем это было на самом деле. Я последовал за рекомендациями Juunas и добавил следующий код в свой класс DbContext Repository:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {

  // get the configuration from the app settings
  var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json")
        .Build();

  // define the database to use
  optionsBuilder.UseSqlServer(config.GetConnectionString("StandardDatabase"));

}

Что отлично работает с инструментами командной строки dotnet ef, и поскольку настройка множественного окружения идет с моим MVC-интерфейсом, который придерживается следующего кода по умолчанию в моем startup.cs, отлично работает.

var builder = new ConfigurationBuilder()
      .SetBasePath(env.ContentRootPath)
      .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
      .AddJsonFile("project.json", optional: true, reloadOnChange: true);

Ответ 3

IDbContextFactory также может помочь. Инструменты командной строки EF и DI могут использовать этот factory для создания экземпляров вашего DBContext. В службах Time Time (например, Migrations) будут обнаружены реализации этого интерфейса, которые находятся в той же сборке, что и производный контекст.

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace MyProject
{
    public class BloggingContextFactory : IDbContextFactory<BloggingContext>
    {
        public BloggingContext Create()
        {
            var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
            optionsBuilder.UseSqlite("Filename=./blog.db");

            return new BloggingContext(optionsBuilder.Options);
        }
    }
}