Подтвердить что ты не робот

Как создать базу данных EF6 с включенными миграциями без использования базы данных обновлений?

В EF5 я полагался на то, что я мог бы воссоздать свою базу данных из модели, используя Database.CreateIfNotExists()

Я должен генерировать Migrations по мере необходимости, но никогда не проверять их на исходный контроль (поскольку они, как правило, являются артефактами цикла разработки). Каждый разработчик затем удалял и воссоздавал свои собственные базы данных по мере необходимости.

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

Этот рабочий процесс больше не работает, поскольку нет возможности сгенерировать базу данных с нуля при включении миграции, без предварительного создания всех миграций и последующего вызова базы данных обновлений. Поскольку вызов add-migration изменяет файл csproj, это делает мои скрипты (которые позволяют нам легко переключаться между ветвями) непригодным для использования.

Миграция включена для контекста "ApplicationDbContext", но база данных не существует или не содержит сопоставленных таблиц. Используйте "Миграции" для создания базы данных и ее таблиц, например, запустив команду "Обновить базу данных" из консоли диспетчера пакетов.

Есть ли способ вернуться к поведению EF5, когда Database.Create создаст текущую версию db?

4b9b3361

Ответ 1

Я использовал CreateDatabaseIfNotExists для инициализации БД и смог использовать базу данных обновлений и запустить мое приложение, и он создаст БД, если он еще не существует. Это, похоже, сломалось с EF 6.0.x.

Это было полезно, но не то, что я использовал.

Что я сделал - это отказаться от существующего кода инициализации и заменить его на следующий код в Global.asax.

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());
        using (MyContext temp = new MyContext())
        {
            temp.Database.Initialize(true);
        }

Примечание. MyContext - это контекст, который я использую, а Configuration - это файл конфигурации, который создается при включении миграции.

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

Edit:

Это код, который я добавил в свой класс контекста. Мне это не нравится так же, как и то, как он работал, но на данный момент он выполняет свою работу. См. Комментарий @Doug к OP о голосовании по CodePlex.

private static readonly Object syncObj = new Object();
public static bool InitializeDatabase()
{
    lock (syncObj)
    {
        using (var temp = new TbdContext())
        {
            ObjectContext oc = null;
            try
            {
                oc = temp.ObjectContext;
            }
            catch (Exception ex)
            {
                //Ignore error
                Console.WriteLine(ex);
            }

            if (oc != null && oc.DatabaseExists())
            {
                return true;
            }
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<TbdContext, Configuration>());
            try
            {
                temp.Database.Initialize(true);
                return true;
            }
            catch (DataException ex)
            {

        }
    }
}

Затем в моем приложении Global.asax.cs Application_Start() я делаю это:

if (databaseInitialized == false)
    databaseInitialized = MyContext.InitializeDatabase();

Edit:

Я обновился до EF 6.1 и нашел, что это больше не работает. (fooobar.com/questions/94718/...) Вот что я сделал, чтобы исправить это:

    private static readonly Object syncObj = new Object();
    public static bool InitializeDatabase()
    {
        lock (syncObj)
        {
            using (var temp = new MyContext())
            {
                if (temp.Database.Exists()) return true;

                var initializer = new MigrateDatabaseToLatestVersion<MyContext, Configuration>();
                Database.SetInitializer(initializer);
                try
                {
                    temp.Database.Initialize(true);
                    return true;
                }
                catch (Exception ex)
                {
                    //Handle Error in some way
                    return false;
                }
            }
        }
    }

Ответ 2

Это работает для меня (до сих пор...):

var connectionString = "Data Source=localhost;Initial Catalog=Chilli;" + 
    "Integrated Security=True;" + 
    "MultipleActiveResultSets=True;Application Name=ChilliDesktop";

//ooops... you have to create a new, blank database if one does not exist
var bld = new SqlConnectionStringBuilder(connectionString);
var dbName = bld.InitialCatalog; //i.e. Chilli

bld.InitialCatalog = "master";

//a connectionstring pointing at Master
var masterConnectionString = bld.ConnectionString; 

using (var cnn = new SqlConnection(masterConnectionString))
{
  var cmdString = string.Format(
     "if not exists (select * from sys.databases where name='{0}')" + 
     "\r\ncreate database {0}",
     dbName);
   using (var cmd = new System.Data.SqlClient.SqlCommand(cmdString,cnn))
   {
     cmd.Connection.Open();
     cmd.ExecuteNonQuery();
   }                
 }


var connectionInfo = 
    new System.Data.Entity.Infrastructure
        .DbConnectionInfo(connectionString, "System.Data.SqlClient");
//new up your auto-created Migrations Configuration class
var config = new Chilli.Context.Migrations.Configuration();
config.TargetDatabase = connectionInfo;
//new up a Migrator
var migrator = new System.Data.Entity.Migrations
    .DbMigrator(config);
migrator.Update();
//you now have a database

//run your Seed method
using (var dc = new Chilli.Context.Context(connectionString))
{
    Chilli.Context.ChilliContextInitializerHelper.Seed(dc);
}

http://softwaremechanik.wordpress.com/2013/11/04/ef6-if-migrations-are-enabled-cannot-createdatabaseifnotexists/

Ответ 3

Вот ответ...

EF Team Triage: Это "По дизайну" и было преднамеренным изменением, которое мы приняли в EF6. Если этот инициализатор используется для создания базы данных, в таблицу __MigrationsHistory добавляется одна запись, которая затем выводит базу данных, не подлежащую использованию с миграциями (поскольку эти инициализаторы не используют ваши миграции для создания базы данных). Это путало большое количество людей в предыдущих выпусках, поэтому мы не планировали автоматически создавать базу данных/схему при включении миграции.

Вы можете использовать инициализатор MigrateDatabaseToLatestVersion, если хотите, чтобы ваши миграции были применены. Если вы хотите удалить базу данных, вы можете легко обернуть ее в пользовательский инициализатор, который включает вызов контекста .Database.Delete().

http://entityframework.codeplex.com/workitem/1689

Ответ 4

К другим застряли. Я закончил это в EF6.

public CatContext(bool forcePreparation)
{
    if (!forcePreparation)
        return;

    if (!Database.Exists() || !Database.CompatibleWithModel(false))
    {
        Database.SetInitializer<CatContext>(new MigrateDatabaseToLatestVersion<CatContext, Configuration>());
    }
    else
    {
        // Database exists and matches the current model.
        // Doing this special thing to avoid the bug that arises sometimes.
        Database.SetInitializer<CatContext>(null);
    }

    Database.Initialize(true);
}

public CatContext()
    : this(forcePreparation: false)
{ }

В моем коде я создаю объект контекста как new CatContext(true).