Ошибка использования базы данных с Entity Framework 4 Code First

У меня есть приложение MVC3 и EF 4 Code First, которое настроено на изменение БД при изменении модели, установив инициализатор БД в DropCreateDatabaseIfModelChanges<TocratesDb> , где TocratesDb является моим производным DbContext .

Теперь я внес изменения в модель, добавив свойства в класс, но когда EF пытается сбросить и воссоздать БД, я получаю следующую ошибку:

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

У меня нет абсолютно никаких других связей в этой базе данных. Я предполагаю, что у моего cDbContext все еще есть открытое соединение с базой данных, но что я могу сделать по этому поводу?

NEW: Теперь моя проблема заключается в том, как воссоздать базу данных на основе модели. Используя более общий IDatabaseInitializer, я теряю это и сам должен его реализовать.

В вашем текущем контексте должно быть открыто соединение, позволяющее удалить базу данных. Проблема в том, что могут быть другие открытые соединения, которые блокируют ваш инициализатор db. Один очень хороший пример – открытие любой таблицы из вашей базы данных в студии управления. Другой возможной проблемой может быть открытие соединений в пуле подключений вашего приложения.

В MS SQL этого можно избежать, например, путем переключения DB в режим SINGLE USER и принудительного закрытия всех подключений и откат неполных транзакций:

 ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE 

Вы можете создать новый intializer, который сначала вызовет эту команду, а затем удалит базу данных. Имейте в виду, что вы должны сами обращаться к соединению с базой данных, потому что ALTER DATABASE и DROP DATABASE должны вызываться в том же соединении.

Редактировать:

Здесь у вас есть пример с использованием шаблона Decorator. Вы можете изменить его и инициализировать внутренний инициализатор внутри конструктора вместо передачи его в качестве параметра.

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

Я обнаружил, что в EF 6 это не выполняется с утверждением ALTER DATABASE statement not allowed within multi-statement transaction ошибки ALTER DATABASE statement not allowed within multi-statement transaction .

Решение заключалось в том, чтобы использовать новую перегрузку поведения транзакции следующим образом:

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

Я была такая же проблема.

Я разрешил его, закрыв соединение, открытое в представлении Server Explorer Visual Studio.

Я понимаю, что это датировано, но я не мог заставить принятое решение работать, поэтому я быстро перевернул решение …

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

Это работает для меня и легко поддерживает посев.

В Visual Studio 2012 окно SQL Explorer Object Explorer может содержать соединение с базой данных. Закрытие окна, и все открытые из него окна освобождают соединение.

Простое закрытие всего моего проекта и его повторное открытие сделали трюк для меня. Это самый простой способ убедиться, что соединения еще не открыты