我正在使用EntityFramework Core命令迁移数据库。我正在使用的命令就像文档建议的那样:dnx。如果迁移适用。问题是在连接字符串中指定AttachDbFileName时,会出现以下错误:无法将数据库文件附加为数据库xxxxxxx。这是我正在使用的连接字符串: 数据源=(LocalDB)\ mssqllocaldb;集成安全性= True;初始目录= EfGetStarted2; AttachDbFileName = D:\ EfGetStarted2.mdf
请帮助您如何将db文件附加到其他位置。 感谢
答案 0 :(得分:0)
可能有一个不同的* .mdf文件已经附加到名为EfGetStarted2的数据库...尝试删除/分离该数据库,然后再试一次。
如果用户LocalDB正在运行,您可能也会遇到问题,因为它没有对路径的正确权限。
答案 1 :(得分:0)
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迁移的“真实世界”场景应该是可行的方法,但也许这个问题的根本原因是相同的......
<强>更新强>
下一个版本将包含support for AttachDBFilename。