实体框架无法删除数据库,数据库正在使用中

Posted

技术标签:

【中文标题】实体框架无法删除数据库,数据库正在使用中【英文标题】:Entity Framework unable to delete database, database in use 【发布时间】:2013-02-24 11:13:12 【问题描述】:

我(和许多其他人一样)遇到了一个问题,即我无法让我的 NUnit 测试删除我的测试夹具 [SetUp] 中的数据库。

我想要达到的目标

我想编写集成测试来测试我的代码并验证预期结果是否存储在数据库中(断言 CRUD 方法)。那,我希望能够实际显示 SqlServer 中的表并查看数据库中的结果如何。最后一部分似乎很难实现......

出了什么问题

我可以连续多次运行我的测试。每次都在[SetUp] 中重新创建数据库,并且测试通过了断言。一旦我想在 SqlServer 中的实际数据库中检查我的结果,它就会付诸东流。从 SqlServer 打开连接后,[SetUp] 方法不允许删除数据库,因为它已打开连接。

我尝试了什么

数据库初始化程序 ALTER 数据库 SET SINGLE_USER WITH ROLLBACK IMMEDIATE Pooling=false 添加到连接字符串

我从this 和this SO 帖子中获得了这些想法。

我有什么

[SetUp] 方法:

    [SetUp]
    public void SetUp()
    
        // TenantSeedInitializer extends the 
        // DropCreateDatabaseAlways<TenantApplicationTestContext> class

        Database.SetInitializer(new TenantSeedInitializer());
        _applicationContext = new TenantApplicationTestContext();
        _applicationContext.Database.ExecuteSqlCommand("ALTER DATABASE " + 
            TenantApplicationTestContext.DatabaseName + 
            " SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
    

[TearDown] 方法:

    [TearDown]
    public void TearDown()
    
        SqlConnection.ClearAllPools();
    

还有一个非常直接的测试:

    [Test]
    public void AddTenant()
    
        // add a new tenant to the database and verify that there
        // there is only one tenant present in the table  
    

正如我所说,连续多次运行这个测试就像一个魅力,直到我尝试在 SqlServer 中打开表。

两种不同的(对我来说未解决的)错误场景

1) 要么我不能查看表格,因为来自 Visual Studio 的连接仍然打开。

数据库“TestTenantDatabase”已经打开,一次只能有一个用户。

添加SqlConnection.ClearAllPools(); 似乎无法解决此问题。

2) 或者我被允许在 SqlServer 中查看表,然后我不再被允许从我的[SetUp] 夹具中删除数据库。

无法删除数据库“TestTenantDatabase”,因为它当前正在使用中。

关闭 SqlServer 是我知道摆脱这种情况的唯一方法。但后来我发现自己在白天重新启动了 SqlServer 很多...(关闭与数据库的连接的选项也会有所帮助,但我找不到它)。

有人可以指导我吗?

【问题讨论】:

你能杀死有问题的连接吗? 我可以关闭 Visual Studio 或 sqlserver,但这非常耗时。我不知道其他解决方案 使用sp_who 列出所有连接,然后使用kill &lt;id&gt; 杀死其中一个。 @thebjorn,我删除了我之前的评论,该评论说我无法让它工作。我可以让它与 kill id 一起工作。所以这是一个起点。至少耗时少。我现在会更加注意下面的答案。也许我能找到一种方法,让我少做一些体力活。谢谢你的评论! 【参考方案1】:

这条消息:

数据库“TestTenantDatabase”已经打开,只能有一个 一个用户。

发生是因为您已将数据库设置为单用户。通常,您会这样做会杀死与数据库的其他连接,并使您的连接成为唯一可以访问它的连接。但是,如果您更改数据库上下文,其他应用程序(如 Visual Studio)可能会连接进来,并成为单一用户,从而有效地将您锁定在外。

在你的设置夹具中试试这个:

use TestTenantDatabase;
alter database TestTenantDatabase set single_user with rollback immediate;
use master;
drop database TestTenantDatabase;

如果你在设置单用户时在数据库中,你将成为单用户。然后,如果您更改为 master 然后在同一批次中删除数据库,它应该会击败任何试图连接到它的人。

另一个选项是设置离线,而不是 single_user,但是,当您删除数据库时,它不会删除数据库 .mdf 和 .ldf(以及任何 .ndf)文件,因此您在重新创建数据库时可能会遇到问题用于另一组测试的数据库。

如果您在运行 single_user 时遇到与死锁相关的错误,请将您的死锁优先级设​​置为高。如果要重用连接,可以在删除后将其恢复正常。

【讨论】:

那也不行。给出完全相同的消息“无法删除数据库“TestTenantDatabase”,因为它当前正在使用中。”。另外我正在尝试使用DropCreateDatabaseAlways&lt;TenantApplicationTestContext&gt; 来删除数据库,这样我就可以在我的业务代码和测试代码中远离手写的 sql 代码。到目前为止,我得到的唯一解决方法是终止进程并重新开始测试。 你可以离线代替single_user,删除数据库,然后自己处理数据库文件。 是的,我以为你会这么说:)。嗯。希望如果这样做会有一些更友好的方式 好的,如果您知道正在使用哪个登录,您可以禁用登录,然后执行答案中的步骤,然后重新启用登录。登录必须不断尝试连接,因此它设法在您退出之前进入。要禁用登录,请执行alter login [&lt;yourlogin&gt;] disable。执行enable 再次启用它。您将需要服务器级别的权限才能运行这些语句。

以上是关于实体框架无法删除数据库,数据库正在使用中的主要内容,如果未能解决你的问题,请参考以下文章

在 WCF 数据服务应用程序中迁移实体框架 6 和 VS2013 后无法更新或删除

无论删除规则如何,都无法删除核心数据实体

实体框架:开发不执行更新和删除的模型

首先在实体框架数据库中级联删除

如何使用实体框架代码优先从数据库中删除所有相关实体

使用实体框架删除大量项目[重复]