"Impossible de supprimer la base de données car elle est actuellement utilisée". Comment réparer?

Ayant ce code simple, je reçois "impossible de supprimer la base de données "test_db" car il est actuellement utilisé "(méthode de nettoyage) pendant que je l'exécute.

[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 a une propriété comme celle-ci

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

Comment forcer mon code à supprimer la base de données? Merci

52
demandé sur Ladislav Mrnka 2011-08-10 04:41:22

7 réponses

Le problème est que votre application détient probablement encore une connexion à la base de données(ou une autre application détient également une connexion). La base de données ne peut pas être supprimée lorsqu'il existe une autre connexion ouverte. Le premier problème peut probablement être résolu en désactivant le regroupement de connexions (ajoutez Pooling=false à votre chaîne de connexion) ou effacez le pool avant de supprimer la base de données (en appelant SqlConnection.ClearAllPools()).

Ces Deux problèmes peuvent être résolus en forçant la base de données à supprimer mais pour cela vous devez personnalisé initialiseur de base de données où vous passez la base de données en mode mono-utilisateur et après cela, supprimez-la. Voici un exemple de la façon d'y parvenir.

61
répondu Ladislav Mrnka 2017-05-23 12:09:58

Je devenais fou avec ça! J'ai une connexion de base de données ouverte à l'intérieur de SQL Server Management Studio (SSMS) et une requête de table ouverte pour voir le résultat de certains tests unitaires. Lors de la ré-exécution des tests dans Visual Studio, je veux toujours drop La base de données même si la connexion est ouverte dans SSMS.

Voici la façon définitive de se débarrasser de Cannot drop database because it is currently in use:

Initialisation De La Base De Données Entity Framework

L'astuce consiste à remplacer la méthode InitializeDatabase dans la coutume Initializer.

Copié la partie pertinente ici pour le bien de good DUPLICATION ... :)

Si la base de données existe déjà, vous pouvez tomber dans le cas d'avoir erreur. L'exception " Impossible de supprimer la base de données car elle est actuellement en cours d'utilisation" peut soulever. Ce problème se produit lorsqu'une connexion active reste connecté à la base de données qu'il est en train d'être supprimer. Une astuce consiste à remplacer la méthode InitializeDatabase et à modifier la base de données. Ce dites à la base de données de fermer toute connexion et si une transaction est ouverte pour annuler celle-ci.

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);
    }
}
35
répondu Leniel Maccaferri 2015-03-27 23:22:15

C'est un (re)initialiseur de base de données vraiment agressif pour le code EF-d'abord avec les migrations; utilisez-le à vos risques et périls mais il semble fonctionner assez régulièrement pour moi. Il le fera;

  1. déconnectez de force tous les autres clients de la base de données
  2. supprimer la base de données.
  3. reconstruire la base de données avec des migrations et exécute la méthode Seed
  4. Prendre des âges! (regardez la limite de délai d'attente pour votre framework de test; un délai d'attente par défaut de 60 secondes peut ne pas suffire)

Voici le classe;

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

    }
}

Utilisez-le comme ceci;

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

J'utilise également le truc 'Pooling=false' De Ladislav Mrnka, mais je ne suis pas sûr que ce soit nécessaire ou juste une mesure de ceinture et d'accolades. Cela contribuera certainement à ralentir davantage le test.

17
répondu Steve Cooper 2014-02-14 11:02:49

Aucune de ces solutions n'a fonctionné pour moi. J'ai fini par écrire une méthode d'extension qui fonctionne:

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();
    }
}
5
répondu Chris McKenzie 2014-03-13 20:36:56

J'essaie d'Ajouter Pooling=false comme Ladislav Mrnka l'a dit mais j'ai toujours eu l'erreur.
J'utilise Sql Server Management Studio et même si je ferme toute la connexion, j'obtiens l'erreur.

Si je ferme Sql Server Management Studio alors la base de données est supprimée :)
J'espère que cela peut aider

1
répondu anthoLB29 2013-12-15 13:36:09

J'ai eu le même message d'erreur. Dans mon cas, je viens de fermer la connexion à la base de données, puis de me reconnecter une fois que le nouveau modèle a été ajouté et qu'un nouveau contrôleur a été échafaudé. C'est cependant une solution très simple et non recommandée pour tous les scénarios si vous souhaitez conserver vos données.

0
répondu user5504242 2016-01-04 09:22:52

J'ai eu le même problème à l'époque. Il s'avère que la solution consiste à fermer la connexion dans L'onglet Explorateur de serveur dans Visual Studio. Alors peut-être que vous pourriez vérifier si la connexion est toujours ouverte dans L'Explorateur de serveur.

0
répondu Sambalado 2017-01-29 04:15:50