使用Entity Framework Core Migration命令時無法附加數據庫文件


我正在使用EntityFramework Core命令遷移數據庫。我使用的命令就像文檔建議的那樣:dnx。如果遷移適用。問題是在連接字符串中指定AttachDbFileName時,會出現以下錯誤:無法將數據庫文件附加為數據庫xxxxxxx。這是我正在使用的連接字符串:Data Source =(LocalDB)\ mssqllocaldb; Integrated Security = True; Initial Catalog = EfGetStarted2; AttachDbFileName = D:\ EfGetStarted2.mdf

請幫助您如何將db文件附加到其他位置。謝謝

一般承認的答案

EF核心似乎有AttachDbFileName的麻煩或根本不處理它。

  • EnsureDeleted將數據庫名稱更改為master,但保留任何AttachDbFileName值,這會導致錯誤,因為我們無法將master數據庫附加到另一個文件。
  • EnsureCreated使用提供的AttachDbFileName值打開連接,這會導致錯誤,因為我們要創建的數據庫文件尚不存在。

EF6有一些邏輯來處理這些用例,請參閱SqlProviderServices.DbCreateDatabase ,所以一切都很好。

作為一種解決方法,我編寫了一些hacky代碼來處理這些場景:

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的支持


熱門答案

可能有一個不同的* .mdf文件已經附加到名為EfGetStarted2的數據庫...嘗試刪除/分離該數據庫,然後再試一次。

如果用戶LocalDB正在運行,您可能也會遇到問題,因為該路徑沒有正確的權限。





許可下: CC-BY-SA
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因