有这个简单的代码,我得到“不能删除数据库”test_db“因为它当前正在使用”(CleanUp方法),因为我运行它。
[TestFixture]
public class ClientRepositoryTest
{
private const string CONNECTION_STRING = "Data Source=.;Initial Catalog=test_db;Trusted_Connection=True";
private DataContext _dataCntx;
[SetUp]
public void Init()
{
Database.SetInitializer(new DropCreateDatabaseAlways<DataContext>());
_dataCntx = new DataContext(CONNECTION_STRING);
_dataCntx.Database.Initialize(true);
}
[TearDown]
public void CleanUp()
{
_dataCntx.Dispose();
Database.Delete(CONNECTION_STRING);
}
}
DataContext有一个这样的属性
public DbSet<Client> Clients { get; set; }
如何强制我的代码删除数据库?谢谢
问题是您的应用程序可能仍然保持与数据库的某些连接(或者另一个应用程序也保持连接)。在有任何其他打开的连接的情况下,无法删除数据库。第一个问题可以通过关闭连接池(将Pooling=false
添加到连接字符串)或在删除数据库之前清除池(通过调用SqlConnection.ClearAllPools()
)来解决。
这两个问题都可以通过强制数据库删除来解决,但为此需要自定义数据库初始化程序,您可以将数据库切换到单用户模式,然后删除它。 Here是如何实现这一目标的一些例子。
我为此疯了!我在SQL Server Management Studio (SSMS)
中有一个开放的数据库连接,并打开一个表查询以查看某些单元测试的结果。当在Visual Studio中重新运行测试时,我希望它始终在drop
数据库,即使在SSMS中打开了连接。
这是摆脱Cannot drop database because it is currently in use
的权威方式:
Entity Framework Database Initialization
诀窍是在自定义InitializeDatabase
中覆盖Initializer
方法。
为了good
重复,这里复制相关部分...... :)
如果数据库已经存在,您可能会遇到错误的情况。 “无法删除数据库,因为它当前正在使用”的异常可以引发。当活动连接保持连接到数据库时,它正在被删除的过程中会发生此问题。一个技巧是覆盖InitializeDatabase方法并更改数据库。这告诉数据库关闭所有连接,如果事务处于打开状态以回滚此事务。
public class CustomInitializer<T> : DropCreateDatabaseAlways<YourContext>
{
public override void InitializeDatabase(YourContext context)
{
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction
, string.Format("ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", context.Database.Connection.Database));
base.InitializeDatabase(context);
}
protected override void Seed(YourContext context)
{
// Seed code goes here...
base.Seed(context);
}
}
这是一个非常积极的数据库(重新)初始化程序,用于EF代码优先迁移;使用它会带来危险,但它似乎对我来说非常重复。它会;
这是班级;
public class DropCreateAndMigrateDatabaseInitializer<TContext, TMigrationsConfiguration>: IDatabaseInitializer<TContext>
where TContext: DbContext
where TMigrationsConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<TContext>, new()
{
public void InitializeDatabase(TContext context)
{
if (context.Database.Exists())
{
// set the database to SINGLE_USER so it can be dropped
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
// drop the database
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "USE master DROP DATABASE [" + context.Database.Connection.Database + "]");
}
var migrator = new MigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration>();
migrator.InitializeDatabase(context);
}
}
像这样使用它;
public static void ResetDb()
{
// rebuild the database
Console.WriteLine("Rebuilding the test database");
var initializer = new DropCreateAndMigrateDatabaseInitializer<MyContext, MyEfProject.Migrations.Configuration>();
Database.SetInitializer<MyContext>initializer);
using (var ctx = new MyContext())
{
ctx.Database.Initialize(force: true);
}
}
我也使用Ladislav Mrnka的'Pooling = false'技巧,但我不确定它是否需要或只是一个带和括号的措施。它肯定会有助于减慢测试速度。
这些解决方案都不适合我。我最终写了一个有效的扩展方法:
private static void KillConnectionsToTheDatabase(this Database database)
{
var databaseName = database.Connection.Database;
const string sqlFormat = @"
USE master;
DECLARE @databaseName VARCHAR(50);
SET @databaseName = '{0}';
declare @kill varchar(8000) = '';
select @kill=@kill+'kill '+convert(varchar(5),spid)+';'
from master..sysprocesses
where dbid=db_id(@databaseName);
exec (@kill);";
var sql = string.Format(sqlFormat, databaseName);
using (var command = database.Connection.CreateCommand())
{
command.CommandText = sql;
command.CommandType = CommandType.Text;
command.Connection.Open();
command.ExecuteNonQuery();
command.Connection.Close();
}
}
我尝试像Ladislav Mrnka一样添加Pooling=false
,但总是得到错误。
我正在使用Sql Server Management Studio,即使我关闭所有连接,我也会收到错误消息。
如果我关闭Sql Server Management Studio,那么数据库将被删除:) 希望这可以有所帮助
我得到了同样的错误。在我的情况下,我只是关闭了与数据库的连接,然后在我的情况下重新连接新模型,并且新的控制器是脚手架。然而,这是一个非常简单的解决方案,如果您想保留数据,不建议用于所有情况。
那时我遇到了同样的问题。原来解决方案是在Visual Studio的“服务器资源管理器”选项卡中关闭连接。因此,您可以检查服务器资源管理器中的连接是否仍然打开。
它很简单,因为你仍然在某处使用相同的db,或者连接仍然是打开的。因此,首先执行“USE master”(如果存在,但通常是),然后删除另一个db。这总是应该工作!
格茨约翰