webentwicklung-frage-antwort-db.com.de

Msgstr "Datenbank kann nicht gelöscht werden, da sie gerade verwendet wird". Wie repariert man?

Mit diesem einfachen Code erhalte ich die Meldung "Datenbank kann nicht gelöscht werden" test_db ", da sie gerade verwendet wird" (CleanUp-Methode), während ich sie ausführe. 

[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 verfügt über eine solche Eigenschaft 

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

Wie kann ich meinen Code dazu zwingen, die Datenbank zu entfernen? Danke

54
YMC

Das Problem ist, dass Ihre Anwendung wahrscheinlich immer noch eine Verbindung zur Datenbank (oder eine andere Anwendung) hat. Die Datenbank kann nicht gelöscht werden, wenn eine andere Verbindung besteht. Das erste Problem kann wahrscheinlich gelöst werden, indem Sie den Verbindungspool deaktivieren (fügen Sie Pooling=false zu Ihrer Verbindungszeichenfolge hinzu) oder löschen Sie den Pool, bevor Sie die Datenbank löschen (durch Aufruf von SqlConnection.ClearAllPools()).

Beide Probleme können gelöst werden, indem die Datenbank zum Löschen gezwungen wird. Dazu benötigen Sie jedoch einen benutzerdefinierten Datenbankinitialisierer, in dem Sie die Datenbank in den Einzelbenutzermodus umschalten und anschließend löschen. Hier ist ein Beispiel, wie man das erreichen kann.

61
Ladislav Mrnka

Ich wurde verrückt damit! Ich habe eine offene Datenbankverbindung in SQL Server Management Studio (SSMS) und eine Tabellenabfrage geöffnet, um das Ergebnis einiger Komponententests anzuzeigen. Wenn Sie die Tests in Visual Studio erneut ausführen, möchte ich, dass drop die Datenbank immer EVEN IF ist.

Hier ist der endgültige Weg, um Cannot drop database because it is currently in use loszuwerden:

Entity Framework-Datenbankinitialisierung

Der Trick besteht darin, die InitializeDatabase-Methode in der benutzerdefinierten Initializer zu überschreiben.

Das relevante Teil wurde hier für goodDUPLICATION ... :) kopiert.

Wenn die Datenbank bereits vorhanden ist, stolpern Sie möglicherweise in den Fall, dass ein Fehler. Die Ausnahme "Datenbank kann nicht gelöscht werden, da sie derzeit .__ ist." in Gebrauch ”kann erhöhen. Dieses Problem tritt auf, wenn eine aktive Verbindung besteht. bleibt mit der Datenbank verbunden, die gerade dabei ist gelöscht Ein Trick ist das Überschreiben der InitializeDatabase-Methode und von Ändern Sie die Datenbank. Dies teilt der Datenbank mit, alle Verbindungen und .__ zu schließen. Wenn eine Transaktion für das Rollback dieser Transaktion geöffnet ist.

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

Dies ist ein wirklich aggressiver (Neu-) Initialisierungs-Assistent für EF-Code-First mit Migrationen. Verwenden Sie es auf Ihre Gefahr, aber es scheint ziemlich wiederholbar für mich zu laufen. Es wird;

  1. Trennen Sie alle anderen Clients zwangsweise von der Datenbank
  2. Löschen Sie die DB.
  3. Erstellen Sie die Datenbank mit Migrationen neu und führen Sie die Seed -Methode aus
  4. Ewig dauern! (Beachten Sie das Timeout-Limit für Ihr Test-Framework; ein Standard-Timeout von 60 Sekunden reicht möglicherweise nicht aus.)

Hier ist die Klasse;

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

    }
}

Verwenden Sie es so;

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

Ich benutze auch den Trick "Pooling = false" von Ladislav Mrnka, aber ich bin mir nicht sicher, ob es erforderlich ist oder nur ein Maßband. Es wird sicherlich dazu beitragen, den Test mehr zu verlangsamen. 

17
Steve Cooper

Keine dieser Lösungen hat für mich funktioniert. Am Ende habe ich eine Erweiterungsmethode geschrieben, die funktioniert:

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

Ich versuche, Pooling=false hinzuzufügen, wie Ladislav Mrnka sagte, aber immer den Fehler bekam.
Ich verwende Sql Server Management Studio und selbst wenn ich die Verbindung schließe, erhalte ich die Fehlermeldung.

Wenn ich Sql Server Management Studio schließe, wird die Datenbank gelöscht :)
Hoffe das kann helfen

1
anthoLB29

Ich habe den gleichen Fehler bekommen. In meinem Fall habe ich nur die Verbindung zur Datenbank geschlossen und dann die Verbindung wieder hergestellt, sobald in meinem Fall das neue Modell hinzugefügt und ein neuer Controller gerüstet wurde. Dies ist jedoch eine sehr einfache Lösung und nicht für alle Szenarien zu empfehlen, wenn Sie Ihre Daten behalten möchten.

0
user5504242

Ich hatte damals das gleiche Problem. Es stellt sich heraus, dass die Lösung darin besteht, die Verbindung auf der Registerkarte Server Explorer in Visual Studio zu schließen. Vielleicht könnten Sie also überprüfen, ob die Verbindung im Server-Explorer noch geöffnet ist.

0
Sambalado