2015-11-30 4 views
14

Я нахожусь в проекте, где мы используем Code First on Entity Framework для нашей базы данных.Программно создавая первые миграции кода

Мы хотим изменить всю нашу непрерывную интеграцию, чтобы потреблять сгенерированный пакет MSI ниже по течению, но с EF, который представляет несколько осложнений.

  • При изменении модели, мы должны сгенерировать Based миграции кода в противном случае пакет будет перерыв (Database против модели)
  • Мы предпочитаем, чтобы удалить создание миграции из команды (на основе https://msdn.microsoft.com/en-us/data/dn481501.aspx)

Я пробовал различные вещи из Интернета, но большинство, похоже, требует AutomaticMigrations быть установлен в true, а также AutomaticMigrationDataLossAllowed (см: http://romiller.com/2012/02/09/running-scripting-migrations-from-code/).

Я попытался воспроизвести то, что Add-Migration делает, просматривая отражатель .NET, но я не могу найти способ вызвать команду System.Data.Entity.Migrations.AddMigrationCommand, которая вызывается через Powershell.

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

Большое спасибо!

+0

Вы хотите, чтобы этот инструмент фактически создавал файлы миграции и добавлял их в проект? Или просто обновите базу данных до вашей текущей схемы кода? Если это последний, почему автоматическая миграция не является вариантом? Если это первый, не можете ли вы просто добавить событие сборки, которое запускает команду «Add-Migration»? – Rob

+0

@Rob Мы пытаемся создать инструмент, посредством которого наш CI может использовать это и генерировать наши миграции для нас в конце фиксации. Это позволит нам автоматически создать MSI из фиксации, чтобы модель оставалась в синхронизации с миграциями, и MSI не будет разбита. Из-за масштаба нашей базы данных автоматическая миграция почти наверняка приведет к автоматической потере данных. 'Add-Migration', похоже, не доступен извне оболочки VS – LukeHennerley

+0

Не могли бы вы пояснить, что« автоматические миграции почти наверняка приведут к автоматической потере данных ». Почему, по вашему мнению, существует какая-либо разница между * вашим скриптом, запуском Add-Migration и EF, выполняющим Add-Migration? Или это просто вы хотите иногда запускать ручную миграцию и хотите избежать смещения авто/ручного? –

ответ

8

Прежде всего, никакой возможности запустить Nuget powershell за пределами визуальной студии (он использует DTE). Кроме того, все, что вы пишете без Visual Studio, нужно вставлять в csproj вручную (но не сложно).

Чтобы показать, как это работает, я посылаю вам несколько строк. Чтобы проверить их, создайте dll MyDll (проектный тест с контекстом и сущностями), а затем вручную включите миграции в MyDll с помощью Enable-Migrations (только для создания Configuration.cs).

После этого вы можете использовать этот кусок кода для генерации исходного кода

DbConnectionInfo connectionStringInfo = new DbConnectionInfo(
    "Server=.;Database=MigrationTest;User=sa;Password=dacambiare", "System.Data.SqlClient"); // We shoud retrieve this from App.config 

ToolingFacade toolingFacade = new ToolingFacade(
    "MyDll", // MigrationAssemblyName. In this case dll should be located in "C:\\Temp\\MigrationTest" dir 
    "MyDll", // ContextAssemblyName. Same as above 
    null, 
    "C:\\Temp\\MigrationTest", // Where the dlls are located 
    "C:\\Temp\\MigrationTest\\App.config", // Insert the right directory and change with Web.config if required 
    "C:\\Temp\\App_Data", 
    connectionStringInfo) 
{ 
    LogInfoDelegate = s => {Console.WriteLine(s);}, 
    LogWarningDelegate = s => { Console.WriteLine("WARNING: " + s); }, 
    LogVerboseDelegate = s => { Console.WriteLine("VERBOSE: " + s); } 
}; 


ScaffoldedMigration scaffoldedMigration = toolingFacade.Scaffold("MyMigName", "C#", "MyAppNameSpace", false); 

Console.WriteLine(scaffoldedMigration.DesignerCode); 
Console.WriteLine("=================="); 
Console.WriteLine(scaffoldedMigration.UserCode); 

// Don't forget the resource file that is in the scaffoldedMigration 

РЕДАКТИРОВАНИЕ
Я забыл пространств имен и часто не используются так что здесь вы

using System; 
using System.Data.Entity.Infrastructure; 
using System.Data.Entity.Migrations.Design; 
4

Не настоящий ответ на ваш вопрос, а скорее мой опыт: я был бы очень осторожен с миграциями, созданными для вас таким образом. Много раз, когда я создавал миграцию (в VS), я просматриваю их. Я проверяю, являются ли предлагаемые изменения тем, что я хочу, чтобы они были, и EF не пытается сделать что-то глупое (например, переименование столбца/таблицы, отбрасывая таблицу и создавая новую).

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

И ваши миграции - это код. Мы делаем рецензирование миграций, прежде чем они смогут перейти к производству. Создание миграции автоматически сделает эти изменения менее заметными и может привести к потере данных в процессе производства.

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

Обновление Просто состоялась дискуссия с коллегой, и возникла еще одна проблема - как бы вы сделали свое местное развитие? Создаете ли вы миграцию на dev-машине, убедитесь, что все работает? Затем удалите миграцию и зарегистрируйте код? и тогда ваш CI снова сгенерирует вашу миграцию? Я думаю, что это ударит ум Dev при работе с EF.

+0

Yup - вам не придется проверять миграцию от разработчиков или это вызовет проблемы – GraemeMiller

+1

@trailmax Наши разработчики (в настоящее время) работают с автоматическими миграциями, мы отбрасываем и воссоздаваем базу данных всякий раз, когда мы делаем изменения модели в среде разработки предотвращать проблемы, возникающие при работе с миграциями на основе кода, внутри команды и внутри исходного контроля. Но вы поднимаете некоторые интересные моменты, о которых я не думал, мы находимся в зачаточном состоянии нашего концерта, используя EF и кодовые миграции, и если бы у нас было наше время снова, мы, вероятно, не пошли бы по EF-маршруту , Из интереса, как вы справляетесь с миграциями на основе кода в своей команде? – LukeHennerley

+0

@ LukeHennerley Автоматические миграции никогда не работали для нас - слишком много вуду. Наша команда вносит изменения в первую кодовую модель, выдает команду 'add-migration', получает миграционные леса - выполняет двойную проверку, если это правильная миграция. Применяет его к локальной базе данных dev, гарантирует, что все работает так, как ожидалось. И редко бывает, что миграция лесов с первого раза правильная. Затем выполняются интеграционные тесты, которые заново сбрасывают БД с нуля. И когда все в порядке, это становится проверенным, после чего разработчик отправляет по электронной почте команду о новой миграции. – trailmax

1

Вы можете использовать System.Data.Entity.Migrations.Design.MigrationScaffolder класс программно генерировать миграции, как так:

[TestMethod] 
public void GenerateTestMigration() 
{ 
    var config = new MyDbMigrationsConfiguration(); 
    var scaffolder = new MigrationScaffolder(config); 
    var pendingMigration = scaffolder.Scaffold("TestMigration"); 
    Trace.WriteLine(pendingMigration.UserCode); 
} 

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

using Microsoft.VisualStudio.TestTools.UnitTesting; 
using System.Data.Entity.Migrations; 
using System.Data.Entity.Migrations.Design; 
using System.Diagnostics; 
using System.Linq; 

namespace YabbaDabbaDoo 
{ 
    [TestClass] 
    public class MigrationTests 
    { 
     [TestMethod] 
     [TestCategory("RunOnBuild")] 
     public void VerifyThereAreNoPendingMigrations() 
     { 
      // Arrange 
      var config = new MyDbMigrationsConfiguration(); 
      var dbMigrator = new DbMigrator(config); 

      // Act 
      var pendingMigrations = dbMigrator.GetPendingMigrations().ToList(); 

      // Visual Assertion 
      Trace.WriteLine(pendingMigrations); 

      // Assert 
      Assert.AreEqual(0, pendingMigrations.Count(), "There are pending EF migrations that need to be ran."); 
     } 

     [TestMethod] 
     [TestCategory("RunOnBuild")] 
     public void VerifyDatabaseIsCompatibleWithModel() 
     { 
      // Arrange 
      var context = new MyDbContext(); 

      // Act 
      var isCompatible = context.Database.CompatibleWithModel(false); 

      // Visual Assertion 
      if (!isCompatible) 
      { 
       var config = new MyDbMigrationsConfiguration(); 
       var scaffolder = new MigrationScaffolder(config); 
       var pendingMigration = scaffolder.Scaffold("MissingMigration"); 

       Trace.WriteLine("Missing Migration:"); 
       Trace.WriteLine(""); 
       Trace.WriteLine(pendingMigration.UserCode); 
      } 

      // Assert 
      Assert.IsTrue(isCompatible, "The EF model is not compatible with the database. An EF migration needs to be created. See output for sample of missing migration."); 
     } 
    } 
} 
Смежные вопросы