实体框架核心迁移 - 连接字符串

时间:2017-11-24 12:23:31

标签: c# .net-core entity-framework-core ef-migrations

我遇到了与迁移一起处理数据库连接字符串的问题。 我有2个项目:

  • 应用

DbContext位于Domain项目中,因此这是我运行迁移的项目。 迁移概念强制我在OnConfiguring中实现DbContext,并在其中指定数据库提供者,例如:

protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
    builder.UseSqlServer("<connection string>");
}

我的问题是我不想使用硬编码连接字符串,原因显而易见,我不能使用ConfigurationManager从配置文件中读取它,因为配置文件在应用程序项目中。

6 个答案:

答案 0 :(得分:4)

我看到的所有示例都涉及对连接字符串进行硬编码或将其放入ASP.NET Core应用程序的设置文件中。

如果您不使用ASP.NET Core,或者也许我不知道不想将本地环境的数据库详细信息提交给源代码管理,则可以尝试使用临时环境变量。

首先,像这样实现IDesignTimeDbContextFactory(注意,IDbContextFactory现在已弃用):

public class AppContextFactory: IDesignTimeDbContextFactory<AppContext>
{
    public AppContextFactory()
    {
        // A parameter-less constructor is required by the EF Core CLI tools.
    }

    public AppContext CreateDbContext(string[] args)
    {
        var connectionString = Environment.GetEnvironmentVariable("EFCORETOOLSDB");
        if (string.IsNullOrEmpty(connectionString))
            throw new InvalidOperationException("The connection string was not set " +
            "in the 'EFCORETOOLSDB' environment variable.");

         var options = new DbContextOptionsBuilder<AppContext>()
            .UseSqlServer(connectionString)
            .Options;
        return new AppContext(options);
    }
}

然后,您可以在调用Update-Database或任何其他EF Core工具时包括环境变量:

$env:EFCORETOOLSDB = "Data Source=(local);Initial Catalog=ApplicationDb;Integrated Security=True"; Update-Database

答案 1 :(得分:1)

我们遇到了同样的问题并且有一个解决方案。 :)

你必须实施IDbContextFactory<TContext> 这样做时,您可以从appsettings.json中读取连接字符串。您也可以使用Add-Migration而不会出现错误,因为覆盖OnConfigure()已经过时了。

示例实施:

public class DomainContextFactory : IDbContextFactory<DomainContext>
{
    public string BasePath { get; protected set; }

    public DomainContext Create()
    {
        var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

        var basePath = AppContext.BaseDirectory;

        return Create(basePath, environmentName);
    }

    public DomainContext Create(DbContextFactoryOptions options)
        => Create(options.ContentRootPath, options.EnvironmentName);

    private DomainContext Create(string basePath, string environmentName)
    {
        BasePath = basePath;
        var configuration = Configuration(basePath, environmentName);
        var connectionString = ConnectionString(configuration.Build());
        return Create(connectionString);
    }

    private DomainContext Create(string connectionString)
    {
        if (string.IsNullOrEmpty(connectionString))
        {
            throw new ArgumentException($"{nameof(connectionString)} is null or empty", nameof(connectionString));
        }
        var optionsBuilder = new DbContextOptionsBuilder<DomainContext>();
        return Configure(connectionString, optionsBuilder);
    }

    protected virtual IConfigurationBuilder Configuration(string basePath, string environmentName)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(basePath)
            .AddJsonFile("constr.json")
            .AddJsonFile($"constr.{environmentName}.json", true)
            .AddEnvironmentVariables();
        return builder;
    }

    protected virtual string ConnectionString(IConfigurationRoot configuration)
    {
        string connectionString = configuration["ConnectionStrings:DefaultConnection"];
        return connectionString;
    }

    protected virtual DomainContext Configure(string connectionString, DbContextOptionsBuilder<DomainContext> builder)
    {
        builder.UseSqlServer(connectionString, opt => opt.UseRowNumberForPaging());

        DomainContext db = new DomainContext(builder.Options);
        return db;
    }


    DomainContext IDbContextFactory<DomainContext>.Create(DbContextFactoryOptions options)
        => Create(options.ContentRootPath, options.EnvironmentName);
}

我们如何使用它:

    public override IServiceResult<IList<Datei>> LoadAllData()
    {
        using (var db = this.DomainContextFactory.Create())
        {
            var files = db.Datei
                .ToListAsync<Datei>();

            return new ServiceResult<IList<Datei>>(files.Result, files.Result.Count);
        }
    }

示例配置

{
  "ConnectionStrings": {
    "DefaultConnection": "Put your connectionstring here"
  }
}

答案 2 :(得分:1)

这就是我的方法,没有很多额外的代码或疯狂。

项目结构:

  • AspNetCoreProject.Web

  • AspNetCoreProject.Data <-DbContext在这里

我的DbContext是使用构造函数设置的,该构造函数允许您注入DbContextOptions

AspNetCoreProject.Data

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

在您的应用程序或Web应用程序中,您通常会设置ConfigureServices

AspNetCoreProject.Web / Startup.cs / ConfigureServices()

services.AddDbContext<MyContext>(options => 
            options.UseSqlServer(Configuration.GetConnectionString("connection"))

现在,如何迁移?好吧,我“欺骗” Visual Studio UI使其按预期工作。

  • 首先,确保您的应用程序(带有AspNetCoreProject.Web的{​​{1}}项目是start up project

  • 第二,打开您的Nuget软件包管理器控制台。在Nuget PM>控制台的顶部,有一个“设置默认项目” 的下拉菜单,将其指向您的Startup.cs或具有AspNetCoreProject.Data类的项目。

  • 正常运行migration commandsDbContext,然后add-migration init

答案 3 :(得分:1)

我在Windows环境变量MsSql.ConnectionString中配置了以下配置时使用了OnConfiguring,并且开始进行ef迁移创建的命令开始起作用:dotnet ef migrations add InitialCreate

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    var connectionString = Environment.GetEnvironmentVariable("MsSql.ConnectionString");
    if(string.IsNullOrEmpty(connectionString))
        throw new ConfigurationErrorsException("Sql server connection string configuration required");
    
    if (!optionsBuilder.IsConfigured)
    {
        optionsBuilder
            .UseSqlServer(connectionString)
            .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
    }
}

要配置环境变量:

  1. 使用Win + R热键组合打开Run命令窗口
  2. 键入systempropertiesadvanced,然后按Enter
  3. Advanced标签上,点击Environment Variables
  4. 点击New...按钮
  5. Variable name字段中,输入MsSql.ConnectionString
  6. Variable value字段中输入您的连接字符串值

确保在添加新变量之后并且在运行dotnet ef相关命令之前重新启动控制台(以及启动控制台的任何程序)

答案 4 :(得分:0)

我在控制台应用程序中使用了DBContext,并且正在使用带有很少参数(例如连接字符串等)的ctor,因为EF Core Migrations使用的默认参数少了ctor,因此没有填充连接字符串迁移失败。

只需添加代码即可在默认ctor中从ConfigurationBuilder获取连接字符串,以通过此操作。

仅在与控制台应用程序和EF Core一起玩,所以这对我来说现在可行。

答案 5 :(得分:0)

假设您的 DbContext 类具有接受 DbContextOptions 类型参数的构造函数,则 dotnet ef 命令对这种情况具有本机支持 - 无需更改代码或额外配置。创建和运行迁移时只需使用“--startup-project”和“--project”参数即可。

例如,假设您有一个“应用程序”项目和一个名为“域”的单独项目,其中实现了 DbContext。

首先在Application项目启动类中的服务提供者中添加DbContext。然后运行以下命令:

dotnet ef database update --startup-project Application --project Domain