Программное создание первых миграций кода
Я нахожусь в проекте, где мы используем Code First on Entity Framework для нашей базы данных.
Мы хотим изменить всю нашу непрерывную интеграцию, чтобы потреблять сгенерированный пакет MSI ниже по течению, но с EF, который представляет несколько осложнений.
Я пробовал разные вещи из Интернета, но для большинства, как представляется, требуется AutomaticMigrations
для установки true
, а также AutomaticMigrationDataLossAllowed
(см.: http://romiller.com/2012/02/09/running-scripting-migrations-from-code/).
Я попытался воспроизвести то, что Add-Migration
делает, просматривая отражатель .NET, но я не могу найти способ вызвать команду System.Data.Entity.Migrations.AddMigrationCommand
, которая вызывается через Powershell.
У кого-нибудь есть идеи вообще о том, как я могу приблизиться к достижению этого, не делая что-то чрезвычайно грязное? Это то, что я думаю, что многие люди захотят сделать/сделали...
Большое спасибо заранее!
Ответы
Ответ 1
Прежде всего, нет возможности запуска Nuget powershell за пределами visual studio (он использует 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;
Ответ 2
Не реальный ответ на ваш вопрос, скорее доля моего опыта: я был бы очень осторожен с миграциями, созданными для вас таким образом. Много раз, когда я создавал миграцию (в VS), я просматриваю их. Я проверяю, являются ли предлагаемые изменения тем, что я хочу, чтобы они были, и EF не пытается делать что-то глупое (например, переименование столбца/таблицы, отбрасывая таблицу и создавая новую).
Также иногда EF пропускает некоторые критические изменения - недавно у меня возникли проблемы с созданием правильных миграций, когда я изменил длины полей nvarchar
. Это также требовало тщательного анализа миграций.
И ваши миграции также являются кодом. Мы делаем рецензирование миграций, прежде чем они смогут перейти к производству. Создание миграции автоматически сделает эти изменения менее заметными и может потенциально привести к потере данных в процессе производства.
И если вы боретесь с миграциями в командной среде, мы решили это путем общения: каждый раз, когда разработчик проверяет новую миграцию, электронные письма отправляются всем другим разработчикам в этом проекте. Исправлены все наши проблемы.
Обновление Только что обсуждалось с коллегой, и возникла еще одна проблема - как бы вы сделали свою локальную разработку? Создаете ли вы миграции на машине dev, убедитесь, что все работает? Затем удалите миграцию и зарегистрируйте код? и тогда ваш CI снова сгенерирует вашу миграцию? Я думаю, что при работе с EF это убьет умы.
Ответ 3
Вы можете использовать класс 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.");
}
}
}