web-dev-qa-db-ja.com

Entity Framework Coreの移行-接続文字列

移行に関連してDB接続文字列を処理するのに問題があります。 2つのプロジェクトがあります。

  • ドメイン
  • 応用

DbContextはDomainプロジェクトにあるため、これは移行を実行するプロジェクトです。移行の概念により、OnConfiguringDbContextを実装し、データベースプロバイダーを指定するように強制されます。例:

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

私の問題は、明らかな理由でハードコードされた接続文字列を使用したくないことです。構成ファイルはアプリケーションプロジェクトにあるため、ConfigurationManagerを使用して構成ファイルから読み取ることはできません。

13
Robert

私が見たすべての例では、接続文字列をハードコーディングするか、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
4
Rory MacLeod

これは、多くの余分なコードや狂気なしで、私がそれを行う方法です。

プロジェクト構造:

  • 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_プロジェクト(_Startup.cs_を含む)が スタートアッププロジェクト であることを確認します。

  • 次に、Nuget Package Managerコンソールを開きます。 Nuget PM>コンソールの上部に、 'Set Default Project'のドロップダウンがあり、これを_AspNetCoreProject.Data_またはDbContextクラスのプロジェクトにポイントします。

  • 移行コマンド を通常どおり実行します。 _add-migration init_その後_update-database_

2
Adam Vincent

同じ問題があり、解決策があります。 :)

IDbContextFactory <TContext> を実装する必要があります。これを行うと、appsettings.jsonから接続文字列を読み取ることができます。 OnConfigure()の上書きは廃止されるため、Add-Migrationをエラーなしで使用することもできます。

サンプル実装:

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"
  }
}
1
user743414