Entity Frameworkコア移行コマンドを使用しているときにデータベースファイルを添付できません

entity-framework-core

質問

私は、EntityFrameworkコアコマンドを移行データベースに使用しています。私が使用しているコマンドは、docs suggests:dnxのようなものです。移行が適用されます。問題は、接続文字列にAttachDbFileNameを指定すると、次のエラーが表示されます。データベースファイルをデータベースxxxxxxxとして接続できません。これは私が使用している接続文字列です:データソース=(LocalDB)\ mssqllocaldb;統合セキュリティ= True;初期カタログ= EfGetStarted2; AttachDbFileName = D:\ EfGetStarted2.mdf

dbファイルを別の場所に接続する方法を助けてください。ありがとう

受け入れられた回答

EFコアはAttachDbFileNameに問題があるか、まったく処理しません。

  • EnsureDeleted マスターにデータベース名を変更しますが、我々は別のファイルにマスター・データベースをアタッチすることはできませんので、エラーにつながるあらゆるAttachDbFileName値を、保持します。
  • EnsureCreated私たちが作成するデータベースのファイルがまだ存在しないため、エラーにつながる提供AttachDbFileName値を、使用して接続を開きます。

EF6には、これらのユースケースを処理するロジックがあります( SqlProviderServices.DbCreateDatabase参照)。

回避策として、私はこれらのシナリオを処理するためのいくつかのコードを書きました:

public static void EnsureDatabase(this DbContext context, bool reset = false)
{
    if (context == null)
        throw new ArgumentNullException(nameof(context));

    if (reset)
    {
        try
        {
            context.Database.EnsureDeleted();
        }
        catch (SqlException ex) when (ex.Number == 1801)
        {
            // HACK: EF doesn't interpret error 1801 as already existing database
            ExecuteStatement(context, BuildDropStatement);
        }
        catch (SqlException ex) when (ex.Number == 1832)
        {
            // nothing to do here (see below)
        }
    }

    try
    {
        context.Database.EnsureCreated();
    }
    catch (SqlException ex) when (ex.Number == 1832)
    {
        // HACK: EF doesn't interpret error 1832 as non existing database
        ExecuteStatement(context, BuildCreateStatement);

        // this takes some time (?)
        WaitDatabaseCreated(context);

        // re-ensure create for tables and stuff
        context.Database.EnsureCreated();
    }
}

private static void WaitDatabaseCreated(DbContext context)
{
    var timeout = DateTime.UtcNow + TimeSpan.FromMinutes(1);

    while (true)
    {
        try
        {
            context.Database.OpenConnection();
            context.Database.CloseConnection();
        }
        catch (SqlException)
        {
            if (DateTime.UtcNow > timeout)
                throw;
            continue;
        }
        break;
    }
}

private static void ExecuteStatement(DbContext context, Func<SqlConnectionStringBuilder, string> statement)
{
    var builder = new SqlConnectionStringBuilder(context.Database.GetDbConnection().ConnectionString);

    using (var connection = new SqlConnection($"Data Source={builder.DataSource}"))
    {
        connection.Open();

        using (var command = connection.CreateCommand())
        {
            command.CommandText = statement(builder);
            command.ExecuteNonQuery();
        }
    }
}

private static string BuildDropStatement(SqlConnectionStringBuilder builder)
{
    var database = builder.InitialCatalog;

    return $"drop database [{database}]";
}

private static string BuildCreateStatement(SqlConnectionStringBuilder builder)
{
    var database = builder.InitialCatalog;

    var datafile = builder.AttachDBFilename;
    var dataname = Path.GetFileNameWithoutExtension(datafile);

    var logfile = Path.ChangeExtension(datafile, ".ldf");
    var logname = dataname + "_log";

    return $"create database [{database}] on primary (name = '{dataname}', filename = '{datafile}') log on (name = '{logname}', filename = '{logfile}')";
}

それは素晴らしいですが、とにかくそれを統合テストに使用しています。 EFの移行を使用する「現実の」シナリオでは、移行する方法が必要ですが、おそらくこの問題の根本的な原因は同じです...

更新

次のバージョンでは、 AttachDBFilenameのサポートが含まれます


人気のある回答

EfGetStarted2という名前のデータベースに別の* .mdfファイルがすでに添付されている可能性があります。そのデータベースを削除/切断してから、もう一度試してみてください。

ユーザーLocalDBが実行されていて、パスに対する正しいアクセス権がない場合は、問題が発生している可能性もあります。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ