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

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

Имея этот простой код, я получаю "Can not drop database" 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 имеет одно свойство, подобное этому

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

Как заставить мой код удалять базу данных? Благодаря

4b9b3361

Ответ 1

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

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

Ответ 2

Я с ума сходил! У меня есть открытое соединение с базой данных внутри 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...:)

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

Ответ 3

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

  • принудительно отключить любые другие клиенты из базы данных
  • Удалить БД.
  • Восстановить БД с помощью миграции и запустить метод Seed
  • Возьми век! (соблюдайте лимит времени ожидания для вашей тестовой среды, по умолчанию 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' трюк, но я не уверен, что это требуется, или только мера с поясом и скобами. Это, безусловно, будет способствовать замедлению теста.

Ответ 4

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

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

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

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

Ответ 6

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

Ответ 7

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