web-dev-qa-db-ja.com

「データベースは現在使用中のため削除できません」。直し方?

この単純なコードを使用すると、「データベース "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にはこのようなプロパティが1つあります

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

コードを強制的にデータベースを削除するにはどうすればよいですか?ありがとう

57
YMC

問題は、アプリケーションがおそらくデータベースへの接続を保持している可能性があることです(または別のアプリケーションも接続を保持しています)。他の開かれた接続がある場合、データベースは削除できません。最初の問題は、おそらく接続プーリングをオフにする(接続文字列に_Pooling=false_を追加する)か、データベースを削除する前にプールをクリアする(SqlConnection.ClearAllPools()を呼び出す)ことで解決できます。

両方の問題は、データベースを強制的に削除することで解決できますが、そのためには、データベースをシングルユーザーモードに切り替えてから削除するカスタムデータベースイニシャライザーが必要です。 ここ は、それを実現する方法の例です。

64
Ladislav Mrnka

これに夢中になっていた! SQL Server Management Studio (SSMS)内でデータベース接続を開いており、いくつかの単体テストの結果を見るためにテーブルクエリを開いています。 Visual Studio内でテストを再実行するとき、データベースにdrop常にEVEN IF接続はSSMSで開かれています。

Cannot drop database because it is currently in useを取り除く決定的な方法は次のとおりです。

Entity Frameworkデータベースの初期化

トリックは、カスタムInitializeDatabase内でInitializerメソッドをオーバーライドすることです。

good[〜#〜] duplication [〜#〜]... :)のために関連部分をここにコピーしました

データベースが既に存在する場合、エラーが発生する可能性があります。例外「現在使用中のためデータベースを削除できません」が発生する可能性があります。この問題は、アクティブな接続が削除中のデータベースに接続されたままになっている場合に発生します。秘Aは、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);
    }
}
39

これは、移行を伴うEFコードファースト向けの非常に積極的なデータベース(再)イニシャライザーです。あなたの危険でそれを使用しますが、私にとってはかなり繰り返し実行されるようです。そうなる;

  1. DBから他のクライアントを強制的に切断します
  2. DBを削除します。
  3. 移行でDBを再構築し、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);
    }
}

Ladislav Mrnkaの 'Pooling = false'トリックも使用しますが、それが必要なのか、それとも単なるベルトとブレースのメジャーなのかはわかりません。それは確かに、テストをさらに遅くすることに貢献します。

18
Steve Cooper

これらのソリューションはどれも私にとってはうまくいきませんでした。私は機能する拡張メソッドを書くことになりました:

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
Chris McKenzie

ラディスラフ・ムンカが言ったようにPooling=falseを追加しようとしましたが、常にエラーが発生しました。
私はSql Server Management Studioを使用しています。すべての接続を閉じてもエラーが発生します。

Sql Server Management Studioを閉じると、データベースが削除されます:)
これが役立つことを願って

1
anthoLB29

同じエラーが発生しました。私の場合、データベースへの接続を閉じた後、新しいモデルが追加され、新しいコントローラーがスキャフォールドされたときに再接続しました。ただし、これは非常に単純なソリューションであり、データを保持する場合はすべてのシナリオに推奨されるわけではありません。

0
user5504242

私は当時同じ問題を抱えていました。解決策は、Visual Studioの[サーバーエクスプローラー]タブで接続を閉じることです。そのため、サーバーエクスプローラーで接続がまだ開いているかどうかを確認できます。

0
Sambalado