【问题标题】:Entity Framework Core 1.0 Connection StringsEntity Framework Core 1.0 连接字符串
【发布时间】:2018-03-16 22:05:22
【问题描述】:

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

  1. DTO
  2. 存储库(实体框架 - 代码优先)
  3. 服务(业务逻辑)
  4. 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 并运行项目,它确实会返回正确的连接字符串,并且如果我们在 appsettings.json 文件中设置连接字符串用户界面,用户界面也将成功连接。

问题: 上面提到的堆栈是我们用于几个“微应用”的,这意味着我们有几个项目连接到几个数据库。我们还想利用 Development、Staging 和 Production 连接字符串。

如果我们使用配置管理器连接字符串,一切对日常操作都有好处;但是,当我们想将实体框架代码用于数据库命令行时,我们需要进入每个要更新的存储库并将 DbContext 更改为硬编码的连接字符串,执行命令,然后在完成后将它们更改回,这变得相当麻烦。

问题: 我们是不是做错了,是否有设置 Entity Framework Core 1.0 堆栈的首选做法,使我们不必手动更改 DbContext,而是全面利用配置文件?

任何方向都将不胜感激!

【问题讨论】:

  • 创建管理连接并返回 Dbcontext 的工厂方法(或工厂类)
  • 为什么不使用普通的 ASP.NET Core 配置而不是使用 ConfigurationManager?
  • 我最初尝试使用 ASP.NET Core 配置,但在类文件和托管环境中使用它时遇到问题。我在docs.asp.net/en/latest/fundamentals/configuration.html 中使用了指南,但是我没有花太多时间在上面,所以我要再试一次。我在每个存储库中也有一个工作单元,所以也许我会尝试处理那里的连接。

标签: c# asp.net-core entity-framework-core


【解决方案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。

【讨论】:

  • 您将如何从应用程序的其他位置访问公共 Configuration 属性,例如在控制器或过滤器中?我宁愿将它设为private 并通过 DI 容器提供给任何需要它的东西:services.AddSingleton&lt;IConfiguration&gt;(Configuration);
  • 我同意,@ProfK。公共属性应该变成私有字段并在容器中注册。出于某种原因,File New Project 创建了公共属性。我会改变答案。
  • @ProfK,问题,如何在任何地方使用 DbContext?可以给个简单的样本看看吗?
  • @Se0ng11 答案不是另一个问题的正确位置。将您的问题作为问题提出,留下评论告诉我它在哪里,如果许多其他人还没有回答,我会回答。
【解决方案2】:

回答:我让这件事变得比实际困难得多。我遵循了 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);

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2018-05-08
      • 1970-01-01
      • 2022-10-25
      • 2020-01-07
      • 1970-01-01
      • 2020-02-20
      • 1970-01-01
      • 2014-02-17
      • 2021-09-20
      相关资源
      最近更新 更多