问题: 我创建了一个随机名称的mdf文件的副本。 我将该名称注入到EF6 DbContext使用的连接字符串中。 它打开正常,我运行查询等,然后我处理上下文。
此时如果我尝试从文件系统中删除temp mdf文件,我无法将其删除;我得到一个"文件正被另一个进程使用"错误。
有人知道在连接关闭时是否可以强制连接断开mdf文件上的锁定? 或者当SqlExpress引擎释放localdb文件锁?
我尝试过使用它:
master.ExecuteCommand(@"ALTER DATABASE [{0}] SET OFFLINE WITH ROLLBACK IMMEDIATE", db);
master.ExecuteCommand(@"exec sp_detach_db '{0}'", db);
......来自: How to detach a LocalDB (SQL Server Express) file in code ......但它对我不起作用,因为我需要这个:
MultipleActiveResultSets=True
在我的连接字符串中,因此无法通过启用MultipleActiveResultSets的连接发出ALTER DATABASE。
谢谢, 克里斯
我为集成测试创建了一个框架,其中每个测试都获得了localdb的副本。这很好用,并且所有测试都可以并行运行 - 特别是如果所有DB的临时文件夹都是RAMDisk文件夹,它的速度非常快。不幸的是,如果我在所有测试运行之后(或在下一次测试开始之前)清理所有dbs,我就会推动RAMDisk的空间限制,所以我想在每次测试后删除每个数据库完成。看起来只要测试引擎/ sqlexpress引擎正在运行,文件就会保持锁定状态。当它结束时,锁被抬起。
答案 0 :(得分:2)
以为我会发布我的解决方案......
答案我在我的问题中发布了一个链接确实是答案,但它是针对较旧版本的localdb,因此不适用于我,并且没有理解机制我没有意识到如何无需挖掘即可修复它。
以下是使用Entity Framework上下文分离和删除mdf文件的代码,无需关闭localdb \ Sqlexpress实例。您只需要确保关闭与数据库的所有连接。 注意:我的db文件名的最右边50个字符包含一个使名称唯一的GUID!
public void CleanupTempLocalDb(DbContext ctx)
{
if (ctx != null)
{
string dbFilename = new SqlConnectionStringBuilder(ctx.Database.Connection.ConnectionString).AttachDBFilename;
ctx.Dispose();
using (var master = new DbContext(@"Data Source=(LocalDB)\MSSQLLocalDB;Initial Catalog=master;MultipleActiveResultSets=False;Integrated Security=True"))
{
var results = master.Database.SqlQuery<string>(string.Format("SELECT name from sys.databases where name like '%{0}'"
, dbFilename.Substring(dbFilename.Length - 50)));
string dbName = results.FirstOrDefault();
if (dbName != null)
{
master.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction,
string.Format("ALTER DATABASE [{0}] SET OFFLINE WITH ROLLBACK IMMEDIATE"
, dbName));
master.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, string.Format("exec sp_detach_db '{0}'"
, dbName));
System.IO.File.Delete(dbFilename);
}
}
}
}
......作为一个......
好的,所以(显然)我对LocalDB工作的理解是有限的。我通过VS2013向我介绍了将一个localdb添加到我的一个项目中,并且从未真正考虑过这些机制。我没有意识到它只是本地sqlexpress的捷径;我认为每个附加的localdb都是一个完全独立的SQL实例 - 而不仅仅是一个连接到某个机器范围的SQLExpress实例的数据库,它有自己的持久主数据库。我从来没有在我的SQL对象浏览器中看到过localdb实例,因为我习惯在SSMS中使用浏览器而不是VS中的那个...事实证明我在服务器浏览器中列出了超过400个数据库(!),没有一个会起作用,因为他们的文件都被删除了!这对我来说似乎有些怪异,事实上,当dbs附加到一个按需启动和停止的SQL实例时,我能够删除文件,这似乎有点傻。现在我理解它,它是有道理的,它适用于我正在使用它的东西,但我从来没有将它用于开发之外的任何东西。
答案 1 :(得分:0)
这是我的EntityFramework Core 1.0解决方案
如您所见,数据库名称可以与其完整文件路径一起使用。
# get unique score values and unique years
uniqScore = unique(dat$score)
uniqYear = unique(dat$year)
# assuming total number of countries remains constant
totalCountries = length(unique(dat$country))
# empty matrix to store results
store = matrix(NA, length(uniqYear), length(uniqScore))
# loop over unique scores
for (i in 1:length(uniqScore)) {
# loop over unique years
for (j in 1:length(uniqYear)) {
# find the number of observations with a given year and score
# subsequently divide it by the total number of possible countries
# to obtain a percentage and save it in store
store[j, i] = length(dat[dat$year == uniqYear[j] &
dat$score == uniqScore[i], 1]) /
totalCountries
}
}
# plot results
matplot(uniqYear, store, type = 'b', pch = 1:3, lty = 2, bty = 'n', las = 1,
ylab = 'Percentage', xlab = 'Year')
legend('topright', legend = uniqScore, pch = 1:3, lty = 2, col = 1:3, bty = 'n')
# or to make it into a dataframe
df = data.frame(percentage = c(store),
score = rep(uniqScore, each = nrow(store)))
答案 2 :(得分:0)
分离本地数据库.mdf的功能。它可以删除文件。
public void DetachLocalDb(string dbFilename)
{
var connectionString = @"Data Source = (LocalDB)\MSSQLLocalDB; Initial Catalog = master; MultipleActiveResultSets = False; Integrated Security = True";
var dbName = dbFilename.ToUpper();
var exec1 = $"ALTER DATABASE[{dbName}] SET OFFLINE WITH ROLLBACK IMMEDIATE";
var exec2 = $"exec sp_detach_db '{dbName}'";
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var sqlCommand = new SqlCommand(exec1, connection))
{
sqlCommand.ExecuteNonQuery();
}
using (var sqlCommand = new SqlCommand(exec2, connection))
{
sqlCommand.ExecuteNonQuery();
}
}
}