51 votes

Erreur d'utilisation de la base de données avec Entity Framework 4 Code First

J'ai un MVC3 et EF 4 du Code de la Première demande, qui est configuré pour modifier la DB lorsque les changements de modèle, par la définition de la DB Initialiseur à un DropCreateDatabaseIfModelChanges<TocratesDb>TocratesDb est mon dérivé DbContext.

J'ai maintenant fait une modification du modèle, par l'ajout de propriétés à une classe, mais quand EF tente de supprimer et de recréer la base de données, j'obtiens l'erreur suivante:

Cannot drop database "Tocrates" because it is currently in use.

Je n'ai absolument aucune autre connexion n'importe où s'ouvre sur cette base de données. Je suppose que mon cDbContext encore d'ouvrir une connexion à la base de données, mais ce que je peux faire à ce sujet?

NOUVEAU: Maintenant mon problème est de savoir comment re-créer la base de données basée sur le modèle. En utilisant le plus général IDatabaseInitializer, j'ai la perdre et d'avoir à l'appliquer moi-même.

46voto

Ladislav Mrnka Points 218632

Votre contexte actuel doit avoir une connexion ouverte pour être en mesure de supprimer la base de données. Le problème est qu'il y a peut être d'autres connexions ouvertes qui permettra de bloquer votre db initialiseur. Un très bel exemple est d'avoir ouvert une table de votre base de données dans management studio. Un autre problème possible qui peut être ouvert des connexions dans le pool de connexion de votre application.

Dans MS SQL cela peut être évité par exemple, basculer DB en mode MONO-UTILISATEUR et en forçant toutes les connexions à être fermé et les transactions incomplètes annulée:

ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE

Vous pouvez créer un nouveau intializer qui va d'abord appel de cette commande, puis supprime la base de données. Être conscient que vous devez gérer une connexion de base de données par vous-mêmes, car ALTER DATABASE et DROP DATABASE doit être appelée sur la même connexion.

Edit:

Ici, vous avez un exemple d'utilisation de pattern Décorateur. Vous pouvez les modifier et de les initialiser intérieure de l'initialiseur à l'intérieur du constructeur au lieu de passer en tant que paramètre.

public class ForceDeleteInitializer : IDatabaseInitializer<Context>
{
    private readonly IDatabaseInitializer<Context> _initializer;

    public ForceDeleteInitializer(IDatabaseInitializer<Context> innerInitializer)
    {
        _initializer = innerInitializer;    
    }

    public void InitializeDatabase(Context context)
    {
        context.Database.SqlCommand("ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
        _initializer.InitializeDatabase(context);
    }
}

41voto

Kevin Kuszyk Points 413

J'ai trouvé dans EF 6 que cela échoue avec une erreur ALTER DATABASE statement not allowed within multi-statement transaction .

La solution consistait à utiliser la nouvelle surcharge de comportement de transaction comme ceci:

 context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
 

21voto

psy Points 1522

J'ai eu le même problème.

Je l'ai résolu en fermant une connexion ouverte sous la vue Explorateur de serveurs de Visual Studio.

13voto

Dave Jellison Points 451

Je me rends compte que c'est daté mais je ne pouvais pas faire fonctionner la solution acceptée alors j'ai lancé une solution rapide ...

 using System;
using System.Data.Entity;

namespace YourCompany.EntityFramework
{
    public class DropDatabaseInitializer<T> : IDatabaseInitializer<T> where T : DbContext, new()
    {
        public DropDatabaseInitializer(Action<T> seed = null)
        {
            Seed = seed ?? delegate {};
        }

        public Action<T> Seed { get; set; }

        public void InitializeDatabase(T context)
        {
            if (context.Database.Exists())
            {
                context.Database.ExecuteSqlCommand("ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
                context.Database.ExecuteSqlCommand("USE master DROP DATABASE [" + context.Database.Connection.Database + "]");
            }

            context.Database.Create();

            Seed(context);
        }
    }
}
 

Cela fonctionne pour moi et prend facilement en charge les semis.

3voto

Edward Brey Points 8771

Dans Visual Studio 2012, la fenêtre de l' explorateur d'objets SQL Server peut contenir une connexion à la base de données. La fermeture de la fenêtre et de toutes les fenêtres ouvertes libère la connexion.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X