52

有了這個簡單的代碼,我得到了「無法刪除數據庫」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; } 

怎樣才能迫使我的代碼刪除數據庫? 謝謝

+0

CTP5已死亡。當前版本是EF 4.1。 –

回答

59

問題是,您的應用程序可能仍然持有一些連接到數據庫(或其他應用程序持有連接以及)。有任何其他打開的連接時,無法刪除數據庫。通過關閉連接池(將Pooling=false添加到連接字符串)或刪除數據庫之前清除池(通過調用SqlConnection.ClearAllPools())可能會解決第一個問題。

這兩個問題都可以通過強制刪除數據庫來解決,但是您需要自定義數據庫初始值設定程序,將數據庫切換到單用戶模式,之後將其刪除。 Here是一些例子,如何實現這一點。

+4

Pooling = false創造了這份工作。謝謝! – YMC

+2

@LadislavMrnka如果我有pooling = false並且我已經設置single_user,但是仍然收到此錯誤消息,那麼該怎麼辦? – ashes999

+1

我仍然有錯誤。我正在使用中密度纖維板。 –

1

我試着加入Pooling=false就像Ladislav Mrnka說的,但總是出錯。
我正在使用Sql服務器管理工​​作室即使我關閉所有的連接,我得到的錯誤。

如果我收SQL Server管理套件那麼數據庫被刪除:)
希望本文能幫助

+1

很可能你並沒有關閉'Sql Server Management Studio'中的所有連接,請注意,通常情況下,你有'TWO'連接在那裏運行,'如果關閉/切換兩個對象瀏覽器和一個當前查詢'他們應該工作 – DrCopyPaste

+1

正如@DrCopyPaste所說,SSMS對保持連接開放給你的數據庫非常積極。除了關閉應用程序,我還沒有找到處理它的好方法。 –

+1

@SteveCooper你可以通過腳本來完成:http://stackoverflow.com/a/11627/2186023無需關閉SSMS,然後在完成初始化/更新後,可以重新使用ssms,它會記住你的最後一個連接(儘管它們丟失了),只需按F5兩次,它將執行第二次 – DrCopyPaste

15

這是EF代碼首先遷移一個非常積極的數據庫(重新)初始化;在你的危險中使用它,但它似乎對我來說非常重複。它會;

  1. 強制斷開任何其他客戶端從DB
  2. 刪除DB。
  3. 用遷移重建數據庫並運行Seed方法
  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); 
    } 
} 

我也用拉吉斯拉夫Mrnka的「池=假」的把戲,但如果它需要或只是一個帶和揹帶措施我不知道。它肯定會有助於更多地放慢測試。

5

這些解決方案都不適用於我。我寫了一個擴展方法,它可以工作:

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 @[email protected]+'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(); 
    } 
} 
+0

而不是使用'database.Connection.CreateCommand ()',我們可以使用'dbContext.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction,sqlString)'。否則這是一個很好的解決方案。 – niaher

+0

請幫助我理解 - database.Connection.CreateCommand()是什麼問題?我沒有遇到任何問題。 謝謝! –

+0

沒有,這只是更詳細的。 – niaher

33

我正在爲此而瘋狂!我在SQL Server Management Studio (SSMS)內部有一個開放的數據庫連接,並打開一個表查詢以查看某些單元測試的結果。當在Visual Studio中重新運行測試時,我希望它到drop數據庫始終爲即使如果連接在SSMS中打開。

這裏是明確的方式來擺脫Cannot drop database because it is currently in use

Entity Framework Database Initialization

關鍵是要覆蓋定製InitializerInitializeDatabase方法。

複製這裏goodDUPLICATION着想相關部分... :)

如果數據庫已存在,則可能跌入具有 錯誤的情況。可以引發異常「無法刪除數據庫,因爲它當前正在使用 」。當活動連接 保持連接到數據庫時,會發生此問題,該數據庫正在被刪除的過程中爲 。一個竅門是重寫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); 
    } 
} 
+1

這是最簡單和最直接的方式來放棄用戶進行自動化測試。 – HackedByChinese

+2

加入'IF EXISTS',它非常完美。 – ericosg

+0

@ericosg如何使用'IF EXISTS'? – Kiquenet

0

我得到了同樣的錯誤。在我的情況下,我只關閉了與數據庫的連接,然後重新連接,在我的情況下,新模型被添加並且新的控制器被腳手架。然而,這是一個非常簡單的解決方案,如果你想保留你的數據,不建議用於所有場景。

0

當時我遇到了同樣的問題。原來,解決方案是關閉Visual Studio中服務器資源管理器選項卡中的連接。所以也許你可以檢查服務器資源管理器中的連接是否仍然打開。

+0

這應該是一個評論 –

相關問題