"Невозможно удалить базу данных, потому что она в настоящее время используется". Как исправить?

имея этот простой код, я получаю "не могу удалить базу данных "test_db", потому что она в настоящее время используется" (метод очистки), когда я ее запускаю.

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

Как заставить мой код удалить базу данных? Спасибо

7 ответов


проблема в том, что ваше приложение, вероятно, все еще имеет некоторое соединение с базой данных (или другое приложение также имеет соединение). База данных не может быть удалена при наличии любого другого открытого соединения. Первая проблема, вероятно, может быть решена путем отключения пула соединений (add Pooling=false в строку подключения) или очистить пул перед удалением базы данных (путем вызова SqlConnection.ClearAllPools()).

обе проблемы могут быть решены путем принудительного удаления базы данных, но для этого вам нужен пользовательский инициализатор базы данных, где вы переключаете базу данных в однопользовательский режим и после этого удаляете ее. здесь это пример того, как этого достичь.


Я схожу с ума! У меня есть открытое соединение с базой данных внутри SQL Server Management Studio (SSMS) и запрос таблицы открыт, чтобы увидеть результат некоторых модульных тестов. При повторном запуске тестов внутри Visual Studio я хочу, чтобы он drop база данных ДАЖЕ ЕСЛИ соединение открыто в SSMS.

вот окончательный способ избавиться от Cannot drop database because it is currently in use:

Инициализация Базы Данных Entity Framework

фокус в том, чтобы переопределить InitializeDatabase метод внутри таможни Initializer.

скопировал соответствующую часть здесь ради good дублирование... :)

если база данных уже существует, вы можете наткнуться на случай наличия ошибка. Исключение " не может удалить базу данных, потому что она в настоящее время в использовании " может поднять. Эта проблема возникает при активном подключении остается подключенным к базе данных, которая находится в процессе удаленный. Фокус в том, чтобы переопределите метод 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);
    }
}

это действительно агрессивный инициализатор базы данных (re) для кода EF-сначала с миграциями; используйте его на свой страх и риск, но он, кажется, работает довольно повторяемо для меня. Будет;

  1. принудительно отключите всех других клиентов от БД
  2. удалить БД.
  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);
    }
}

Я также использую трюк Ладислава Мрнки "Pooling=false", но я не уверен, требуется ли это или просто мера ремня и скобок. Это, безусловно, будет способствовать замедлению теста больше.


ни одно из этих решений работал для меня. Я закончил писать метод расширения, который работает:

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

Я пытаюсь добавить Pooling=false Как Ладислав Mrnka говорит, но всегда получал ошибку.
Я использую Среда Sql Server Management Studio и даже если я закрою все соединение, я получу ошибку.

Если я закрою Среда Sql Server Management Studio затем база данных будет удалена :)
Надеюсь, это может помочь


Я получил ту же ошибку. В моем случае я просто закрыл соединение с базой данных, а затем повторно подключился, как только в моем случае была добавлена новая модель и новый контроллер был подмостками. Однако это очень простое решение и не рекомендуется для всех сценариев, если вы хотите сохранить ваши данные.


тогда у меня была такая же проблема. Оказывается, решение состоит в том, чтобы закрыть соединение на вкладке Server Explorer в Visual Studio. Поэтому, возможно, вы могли бы проверить, открыто ли соединение в Проводнике сервера.