2016-03-05 1 views
4

Есть ли простой способ вручную запустить метод Seed() миграции Entity Framework из консоли диспетчера пакетов, в том числе после миграции Down() Update-Database -TargetMigration foo)? Ответ на «Run Code First Migration Seed Method without a migration» описывает, как вручную запустить метод Seed(), который должен вызвать Update-Database, но это не работает, когда база данных находится на более старой миграции и не должна обновляться. Тот же вопрос задавали в «How to run Seed() method of Configuration class of migrations», но его задавали как часть многочастного вопроса, и эта часть остается без ответа (хотя весь вопрос отмечен как ответ).Ручной запуск метода миграции сущностей Framework Entity Framework, в том числе после переноса Down()

Я спрашиваю, потому что у меня есть код очистки, который необходимо запустить после того, как была применена миграция. Вызов из Seed() отлично подходит для миграции Up(). Однако я не знаю, как легко называть его для миграции Down(). Мне нужен простой, один или два лайнера, который будет работать от менеджера пакетов. Я знаю, что я мог бы вызвать метод C# после вызова [Reflection.Assembly] :: LoadFile() для всех необходимых DLL, но есть достаточно зависимостей, что это было бы громоздким и подверженным ошибкам.

Я знаю, что Seed() не является идеальным местом для кода очистки миграции Down(), чтобы добавить некоторый контекст на основе ответа DrewJordan), но использование Down(), к сожалению, не является жизнеспособным по нескольким причинам. С практической точки зрения, это нежизнеспособно, потому что очистка должна конвертировать несколько гигабайтных данных, и это вызвало сбой SQL Server Express, когда я попробовал простую копию в Down(), вероятно, потому, что результирующий размер транзакции был огромным. Во-вторых, даже с гипотетической точки зрения, я не верю, что есть способ конвертировать данные в объеме, необходимом в Down(), потому что текущие строки SQL не могут быть прочитаны в C# как часть транзакции и преобразование данных должен состояться в C#. Подробнее об этом ограничении см. Мой другой вопрос: «Transform data using c# during Entity Framework migration». Некоторый компромисс дизайна был необходим, чтобы заставить очистку работать, и я использовал Seed() как этот компромисс. Код очистки не нужно запускать из Seed() как таковой, но я не знаю, что еще можно вызвать из диспетчера пакетов без изменения текущей миграции.

Существует еще один сценарий, в котором было бы полезно вызывать Seed() или другой код очистки сам по себе, не изменяя текущую миграцию. Рассмотрим сценарий, в котором произошла ошибка в методе Seed()/cleanup. Вы исправляете ошибку и хотите повторно запустить ее, не меняя текущую миграцию. Включение логики очистки в Down() не решит проблему, потому что Down() не будет вызываться, когда база данных уже находится в этой миграции.

+1

Я боюсь, что это не может достигаются с помощью метода Seed. Возможно, вам захочется развить EntityFramework и добавить туда перехват миграции, но, скорее всего, вам просто нужно подумать о другом способе реализации этого. В чем причина этой огромной очистки кода для каждой миграции? –

+0

@raderick Whoa - Я не понял, что источник доступен для Entity Framework. Благодаря! Я собираюсь копать его, чтобы увидеть, могу ли я найти другое обходное решение. ... Очистка предназначена для одной конкретной миграции, просто не представляется возможным сделать преобразование в Up()/Down(), потому что преобразование выполняется в C#. Набор данных - это огромное. – twm

+0

Можете ли вы достичь своей цели, просто добавив этот код миграции в качестве модульного теста и отметьте его атрибутом [Игнорировать] и запустите его вручную? –

ответ

1

Я понимаю, что вы спросили его запустить с консоли PM: AFAIK это невозможно. Этот вариант использования не является тем, что Seed предназначен для: я бы порекомендовал, если у вас есть изменения, сделанные в методе Down, либо для записи сценариев SQL для запуска, либо для создания контекста в Down и делать что угодно.

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

Если вы действительно, действительно думаю, что это хорошая идея, вы можете добавить метод в конфигурацию:

public void CallSeed() 
{ 
    using (var c = new Context()) // create your context 
    { 
     Seed(c); 
    } 
} 

И вызвать его из Даун:

var c = new Configuration(); 
c.CallSeed(); 
+0

Спасибо за ответ. Я бы хотел использовать Down() для очистки, но, к сожалению, он не является жизнеспособным для конверсий данных, где преобразование должно происходить в C#, а также не является жизнеспособным для больших преобразований. Я обновил свой вопрос, чтобы расширить его. – twm

0

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

Идея состоит в том, чтобы скомпоновать другую команду миграции, которая может быть запущена из диспетчера пакетов и которая не будет изменять саму базу - я буду использовать Get-Migrations. Это позволит команде диспетчера пакетов выполнить тяжелую работу по поиску правильных конфигураций, загрузке правых сборок и т. Д. Я свяжусь с этой командой, вызвав мой код очистки из конструктора моего подкласса DbMigrationsConfiguration. Я хочу только запустить код очистки намеренно, причем не каждый раз, когда конфигурация сконфигурирована, поэтому я также проверю переменную среды-дозорного, прежде чем запускать код очистки. Позже я планирую переместить код очистки из Seed(), чтобы отделить его от фактического посева, но поскольку другие спрашивали о запуске Seed() в прошлом вручную, я буду использовать это в качестве примера здесь.

Я изменил мой DbMigrationsConfiguration подкласс следующим образом:

internal sealed class Configuration : DbMigrationsConfiguration<TimsDB> 
{ 

    public Configuration() 
    { 
     if ("true".Equals(Environment.GetEnvironmentVariable("RUN_SEED"))) 
      using (TimsDB db = new TimsDB()) 
      { 
       Database.SetInitializer<TimsDB>(null); 
       Seed(db); 
      } 
     } 
    } 

    ... 

} 

Это может быть использован для вызова Seed() метод вручную из пакета-менеджер:

PM> $Env:RUN_SEED = "true" 
PM> Get-Migrations 
PM> $Env:RUN_SEED = "false" 
Смежные вопросы