“无法删除数据库,因为它当前正在使用”。如何修复?

发布于 2024-11-28 18:54:48 字数 809 浏览 0 评论 0原文

有了这个简单的代码,我在运行它时得到“无法删除数据库“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; }

How can force my code to remove database? 谢谢

Having this simple code I get "Cannot drop database "test_db" because it is currently in use" (CleanUp method) as I run it.

[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 has one property like this

 public DbSet<Client> Clients { get; set; }

How can force my code to remove database?
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

枕头说它不想醒 2024-12-05 18:54:48

问题是您的应用程序可能仍然保持与数据库的某些连接(或者另一个应用程序也保持连接)。如果存在任何其他打开的连接,则无法删除数据库。第一个问题可以通过关闭连接池(将 Pooling=false 添加到连接字符串)或在删除数据库之前清除连接池(通过调用 SqlConnection.ClearAllPools()< /代码>)。

这两个问题都可以通过强制删除数据库来解决,但为此您需要自定义数据库初始化程序,将数据库切换到单用户模式,然后将其删除。 这里是一些示例如何实现这一目标。

The problem is that your application probably still holds some connection to the database (or another application holds connection as well). Database cannot be deleted where there is any other opened connection. The first problem can be probably solved by turning connection pooling off (add Pooling=false to your connection string) or clear the pool before you delete the database (by calling SqlConnection.ClearAllPools()).

Both problems can be solved by forcing database to delete but for that you need custom database initializer where you switch the database to single user mode and after that delete it. Here is some example how to achieve that.

甲如呢乙后呢 2024-12-05 18:54:48

我简直要疯了!我在 SQL Server Management Studio (SSMS) 中有一个打开的数据库连接,并且打开了一个表查询以查看一些单元测试的结果。在 Visual Studio 中重新运行测试时,我希望它始终删除数据库,即使连接在 SSMS 中打开。

这是摆脱无法删除数据库,因为它当前正在使用的明确方法:

Entity框架数据库初始化

技巧是重写自定义Initializer 内的InitializeDatabase 方法。

为了重复而在此处复制了相关部分...:)

如果数据库已经存在,你可能会遇到这样的情况
一个错误。异常“无法删除数据库,因为它当前是
使用中”可以提高。当活动连接时会出现此问题
保持与正在处理的数据库的连接
已删除。一个技巧是重写 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);
    }
}

I was going crazy with this! I have an open database connection inside SQL Server Management Studio (SSMS) and a table query open to see the result of some unit tests. When re-running the tests inside Visual Studio I want it to drop the database always EVEN IF the connection is open in SSMS.

Here's the definitive way to get rid of Cannot drop database because it is currently in use:

Entity Framework Database Initialization

The trick is to override InitializeDatabase method inside the custom Initializer.

Copied relevant part here for the sake of good DUPLICATION... :)

If the database already exist, you may stumble into the case of having
an error. The exception “Cannot drop database because it is currently
in use” can raise. This problem occurs when an active connection
remains connected to the database that it is in the process of being
deleted. A trick is to override the InitializeDatabase method and to
alter the database. This tell the database to close all connection and
if a transaction is open to rollback this one.

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);
    }
}
浪推晚风 2024-12-05 18:54:48

这是一个非常激进的数据库(重新)初始化程序,适用于带有迁移的 EF 代码优先;使用它是有风险的,但它对我来说似乎可以重复运行。会的;

  1. 强制断开任何其他客户端与数据库的连接
  2. 删除数据库。
  3. 通过迁移重建数据库并运行种子方法
  4. 需要很长时间! (注意测试框架的超时限制;默认的 60 秒超时可能不够)

这是课程;

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”技巧,但我不确定它是否是必需的,或者只是一种腰带和支架措施。它肯定会进一步减慢测试速度。

This is a really aggressive database (re)initializer for EF code-first with migrations; use it at your peril but it seems to run pretty repeatably for me. It will;

  1. Forcibly disconnect any other clients from the DB
  2. Delete the DB.
  3. Rebuild the DB with migrations and runs the Seed method
  4. Take ages! (watch the timeout limit for your test framework; a default 60 second timeout might not be enough)

Here's the class;

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);

    }
}

Use it like this;

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);
    }
}

I also use Ladislav Mrnka's 'Pooling=false' trick, but I'm not sure if it's required or just a belt-and-braces measure. It'll certainly contribute to slowing down the test more.

终遇你 2024-12-05 18:54:48

这些解决方案都不适合我。我最终编写了一个有效的扩展方法:

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();
    }
}

None of those solutions worked for me. I ended up writing an extension method that works:

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();
    }
}
心在旅行 2024-12-05 18:54:48

我尝试像 Ladislav Mrnka 所说的那样添加 Pooling=false 但总是收到错误。
我正在使用 Sql Server Management Studio,即使关闭所有连接,也会收到错误。

如果我关闭Sql Server Management Studio,则数据库将被删除:)
希望这能有所帮助

I try adding Pooling=false like Ladislav Mrnka said but always got the error.
I'm using Sql Server Management Studio and even if I close all the connection, I get the error.

If I close Sql Server Management Studio then the Database is deleted :)
Hope this can helps

天煞孤星 2024-12-05 18:54:48

我遇到了同样的错误。就我而言,我只是关闭了与数据库的连接,然后在添加新模型并搭建新控制器后重新连接。然而,这是一个非常简单的解决方案,如果您想保留数据,不建议在所有情况下使用。

I got the same error. In my case, I just closed the connection to the database and then re-connected once the in my case the new model was added and a new controller was scaffolded. That is however a very simple solution and not recommended for all scenarios if you want to keep your data.

初见你 2024-12-05 18:54:48

我当时也遇到了同样的问题。事实证明,解决方案是在 Visual Studio 的“服务器资源管理器”选项卡中关闭连接。因此,也许您可​​以在服务器资源管理器中检查连接是否仍然打开。

I got the same problem back then. Turns out the solution is to close the connection in Server Explorer tab in Visual Studio. So maybe you could check whether the connection is still open in the Server Explorer.

深海夜未眠 2024-12-05 18:54:48

这很简单,因为您仍在某处使用相同的数据库,或者连接仍然打开。
因此,只需先执行“USE master”(如果存在,但通常是),然后删除其他数据库。这总是应该有效!

约翰·格兹

Its simple because u're still using the same db somewhere, or a connection is still open.
So just execute "USE master" first (if exist, but usually is) and then drop the other db. This always should work!

Grz John

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文