Ошибка базы данных при использовании Entity Framework 4 Code First - PullRequest
51 голосов
/ 13 марта 2011

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

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

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

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

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

Ответы [ 6 ]

46 голосов
/ 13 марта 2011

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

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

ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE

Вы можете создать новый инициализатор, который сначала вызовет эту команду, а затем отбросит базу данных.Помните, что вы должны сами обрабатывать соединение с базой данных, потому что 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);
    }
}
41 голосов
/ 14 ноября 2013

Я обнаружил, что в EF 6 это происходит с ошибкой 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");
21 голосов
/ 28 декабря 2011

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

Я решил это, закрыв соединение, открытое в представлении обозревателя серверов Visual Studio.

13 голосов
/ 25 мая 2012

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

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

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

3 голосов
/ 01 февраля 2013

В Visual Studio 2012 окно Обозреватель объектов SQL Server может содержать соединение с базой данных.Закрытие окна и все открытые окна освобождают соединение.

0 голосов
/ 27 ноября 2016

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

...