Entity Framework Core migration - connection string

為{幸葍}努か 提交于 2019-12-21 03:20:53

问题


I'm having a problem to handle the DB connection string in conjunction with migrations. I have 2 projects:

  • Domain
  • Application

The DbContext is in the Domain project, so this is the project I run migrations against. The migrations concept enforces me to implement OnConfiguring in my DbContext and therein specify the database provider, eg:

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

My problem is that I don't want to use a hard coded connection string, for obvious reasons, and I cannot use ConfigurationManager to read it from the config file since the config file is in the application project.


回答1:


All the examples I've seen involve either hard-coding the connection string or putting it in my ASP.NET Core application's settings files.

If you aren't using ASP.NET Core, or maybe, I don't know, don't want to have your local environment's database details committed to source control, you can try using a temporary environment variable.

First, implement IDesignTimeDbContextFactory like this (note that IDbContextFactory is now deprecated):

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

Then, you can include the environment variable when you call Update-Database, or any of the other EF Core tools:

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



回答2:


Here's how I do it, without a lot of extra code or craziness.

Project Structure:

  • AspNetCoreProject.Web

  • AspNetCoreProject.Data <-- DbContext here

My DbContext is set up with the constructor that allows you to inject the DbContextOptions

AspNetCoreProject.Data

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

In your application or web application, you set up your ConfigureServices normally.

AspNetCoreProject.Web / Startup.cs / ConfigureServices()

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

Now, what about migrations? Well, I "trick" the Visual Studio UI into working as expected.

  • First, make sure your application (AspNetCoreProject.Web project with Startup.cs) is the start up project.

  • Second, open up your Nuget Package Manager Console. At the top of the Nuget PM> Console, there's a dropdown for 'Set Default Project', point this to your AspNetCoreProject.Data or project with the DbContext class.

  • Run your migration commands normally. add-migration init then update-database




回答3:


We've had a same issue and there is a solution. :)

You have to implement IDbContextFactory<TContext> When doing so you can read the connectionstrings from your appsettings.json. You can also use Add-Migration without errors, because overwriting OnConfigure() is obsolete then.

Sample implementation:

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

How we use it:

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

sample config

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


来源:https://stackoverflow.com/questions/47473277/entity-framework-core-migration-connection-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!