首页 文章

实体框架核心1.0连接字符串

提问于
浏览
12

我们正在开发一个不同的大型ASP.NET Core MVC 1.0应用程序 . 我们的每个应用程序有4层,如下所示:

  • DTO

  • 存储库(实体框架 - 代码优先)

  • 服务(业务逻辑)

  • 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");

}

该项目作为独立的ASP.NET Core 1.0项目位于MVC项目之外 . 它还有一个空的Program.cs文件,它似乎是执行代码到数据库命令行所必需的(dotnet ef migrations add和dotnet ef database update) .

我们在DbConext中有一个硬编码连接字符串的原因是因为当我们使用下面的代码时,在执行dotnet ef命令时,我们得到一个对象引用未设置为对象异常的实例 .

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {

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

  }

但是,由于我们有一个Program.cs,如果我们为连接字符串添加Debug.WriteLine并运行项目,它会返回正确的连接字符串,如果我们在UI中的appsettings.json文件中设置连接字符串,用户界面也将成功连接 .

THE ISSUE: 上面提到的堆栈是我们用于几个"Micro Apps"的,这意味着我们有几个连接到多个数据库的项目 . 我们还希望利用Development,Staging和Production连接字符串 .

如果我们使用Configuration Manager连接字符串,一切都适合日常操作;但是,当我们想要将Entity Frameworks代码用于数据库命令行时,我们需要进入我们想要更新的每个存储库,并将DbContext更改为硬编码连接字符串,执行命令,然后将它们更改回完成时,这变得非常麻烦 .

THE QUESTION: 我们是否只是这样做错误,是否有一种 Build 实体框架核心1.0堆栈的首选做法,它允许我们不必手动更改DbContext但是充分利用配置文件?

任何方向将不胜感激!

3 回答

  • 10

    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

    ANSWER: 我实际上比实际上要困难得多 . 我按照Juunas的建议,在我的Repository DbContext类中添加了以下代码:

    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 UI在我的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);
    
  • 16

    IDbContextFactory也可能有所帮助 . EF命令行工具和DI可以使用此工厂来创建DBContext的实例 . 设计时服务(例如,迁移)将发现此接口的实现与派生上下文在同一程序集中 .

    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);
            }
        }
    }
    

相关问题