Базата данни не може да бъде премахната, защото в момента се използва. Как да поправя?

Имайки този прост код, получавам „Не мога да премахна базата данни „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; }

Как мога да принудя моя код да премахне базата данни? Благодаря


comment
CTP5 е мъртъв. Текущата версия е EF 4.1.   -  person Ladislav Mrnka    schedule 10.08.2011


Отговори (8)


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

И двата проблема могат да бъдат решени чрез принудително изтриване на база данни, но за това се нуждаете от персонализиран инициализатор на база данни, където превключвате базата данни в режим на един потребител и след това я изтривате. Ето един пример как да го постигнем.

person Ladislav Mrnka    schedule 10.08.2011
comment
Pooling=false свърши работата. Благодаря! - person YMC; 10.08.2011
comment
@LadislavMrnka Какво ще кажете, ако имам pooling=false и вече задавам single_user, но все още получавам това съобщение за грешка? - person ashes999; 07.12.2011

Бях полудял с това! Имам отворена връзка с база данни вътре в 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);
    }
}
person Leniel Maccaferri    schedule 10.07.2014
comment
Това беше най-лесният и директен начин за пускане на потребители за автоматизирани тестове. - person moribvndvs; 13.11.2014
comment
Добавете IF EXISTS и е перфектно. - person ericosg; 03.11.2015
comment
@ericosg Как се използва IF EXISTS? - person Kiquenet; 03.06.2017
comment
Работи ли за mdf файлове с помощта на Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\wingtiptoys.mdf;Integrated Security=True? - person Kiquenet; 03.06.2017
comment
@Kiquenet като това stackoverflow.com/questions/679000/ - person ericosg; 05.06.2017

Това е наистина агресивен (ре)инициализатор на база данни за EF код на първо място с миграции; използвайте го на свой риск, но изглежда, че работи доста повтарящо се за мен. Ще;

  1. Принудително изключете всички други клиенти от базата данни
  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', но не съм сигурен дали е задължителен или просто мярка за колан и презрамки. Това със сигурност ще допринесе за забавяне на теста.

person Steve Cooper    schedule 14.02.2014

Нито едно от тези решения не работи за мен. В крайна сметка написах метод за разширение, който работи:

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();
    }
}
person Chris McKenzie    schedule 13.03.2014
comment
Вместо да използваме database.Connection.CreateCommand(), можем да използваме dbContext.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sqlString). Иначе е хубаво решение. - person niaher; 03.11.2015
comment
Моля, помогнете ми да разбера - какъв е проблемът с database.Connection.CreateCommand()? Не съм имал никакви проблеми. Благодаря! - person Chris McKenzie; 03.11.2015
comment
Никакви, просто е по-многословно, това е всичко. - person niaher; 05.11.2015
comment
Как се използва ? Database.SetInitializer(new EventDatabaseInitializer()); ? - person Kiquenet; 03.06.2017

Опитвам се да добавя Pooling=false, както каза Ладислав Мърнка, но винаги получавам грешката.
Използвам Sql Server Management Studio и дори да затворя цялата връзка, получавам грешката.

Ако затворя Sql Server Management Studio, тогава базата данни се изтрива :)
Надявам се, че това може да помогне

person anthoLB29    schedule 15.12.2013
comment
най-вероятно не сте затворили всички връзки в Sql Server Management Studio, имайте предвид, че обикновено имате TWO връзки, работещи там, one for the object explorer AND one for the current query ако затворите/превключите и двете, трябва да работи - person DrCopyPaste; 28.01.2014
comment
Както казва @DrCopyPaste, SSMS е доста агресивен относно поддържането на отворена връзка към вашата DB. Не намерих добър начин да се справя, освен затваряне на приложението. - person Steve Cooper; 13.02.2014
comment
@SteveCooper можете да го направите чрез скрипт: stackoverflow.com/a/11627/2186023 няма нужда да изключвате SSMS, тогава след като завършите инициализацията/актуализацията, можете да използвате повторно ssms, той ще запомни последните ви връзки (въпреки че са загубени), просто натиснете F5 два пъти, той ще се изпълни втория път - person DrCopyPaste; 13.02.2014

Получих същата грешка. В моя случай просто затворих връзката с базата данни и след това се свързах отново, след като в моя случай новият модел беше добавен и нов контролер беше скеле. Това обаче е много просто решение и не се препоръчва за всички сценарии, ако искате да запазите данните си.

person user5504242    schedule 04.01.2016

Имах същия проблем тогава. Оказва се, че решението е да затворите връзката в раздела Server Explorer във Visual Studio. Така че може би можете да проверите дали връзката все още е отворена в Server Explorer.

person Sambalado    schedule 29.01.2017

Това е просто, защото все още използвате същата база данни някъде или връзката все още е отворена. Така че просто първо изпълнете "USE master" (ако съществува, но обикновено е) и след това пуснете другия db. Това винаги трябва да работи!

Гръц Джон

person John Schellingerhout    schedule 07.03.2019