Entity Framework Migrations: включение оператора Go только в - Script вывода
В рамках планирования миграции Entity Framework, чтобы отлаживать перемещение данных, я часто использовал параметр - Script для генерации script.
Затем я мог бы взять этот script в Query Analyzer и перенести его в транзакцию, чтобы проверить его вручную.
Я столкнулся с ситуацией, когда нам понадобилось приложение Go для правильного выполнения script. Следующий код был добавлен в перенос, чтобы вывести Go в нужное место.
Sql("GO");
Это добавляет оператор GO в правильное положение, когда используется - Script. Но когда - Script не используется. Я получаю исключение...
System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'.
Есть ли безопасный способ добавить команду Go к script?
Ответы
Ответ 1
internal sealed class Configuration : DbMigrationsConfiguration<Context>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
const string providerInvariantName = "System.Data.SqlClient";
SetSqlGenerator(providerInvariantName, new BatchingMigrationSqlGenerator(GetSqlGenerator(providerInvariantName)));
}
protected override void Seed(Context context)
{
}
}
internal class BatchingMigrationSqlGenerator : MigrationSqlGenerator
{
private readonly MigrationSqlGenerator migrationSqlGenerator;
public BatchingMigrationSqlGenerator(MigrationSqlGenerator migrationSqlGenerator)
{
this.migrationSqlGenerator = migrationSqlGenerator;
}
public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
{
var migrationStatements = migrationSqlGenerator.Generate(migrationOperations, providerManifestToken).ToArray();
foreach (var migrationStatement in migrationStatements)
{
migrationStatement.BatchTerminator = "GO";
}
return migrationStatements;
}
}
Ответ 2
Я недавно попал в ту же ситуацию. Мои миграции EF-кода часто представляют новую таблицу или столбец, а затем я также переношу данные с помощью Sql (...) в те миграции, которые иногда хотят ссылаться на новую таблицу/столбец. Как вы указали, при запуске в качестве переноса кода EF каждый оператор, как представляется, выдается как дискретная партия для БД, и, следовательно, нет никаких проблем. Однако, чтобы удовлетворить ограничениям производственного развертывания, мы превращаем набор миграций кода из спринта в один script (с использованием - Script) для представления одной совокупной миграции SQL script для команды развертывания. Этот файл script иногда терпит неудачу, как вы указали, из-за того, что он пытается обработать одну партию T SQL из одной миграции кода, где более поздние операторы пытаются ссылаться на структуру, которая была определена ранее в пакете.
Мне не нравится один из двух подходов, которые я принял сейчас, чтобы смягчить это, но вот они:
а. Если я тогда подумаю об этом, я разделил миграцию кода на две миграции, так что, когда они написаны сценарием, они состоят из двух (или более) отдельных партий. Мне это не нравится, потому что нет никакой обратной связи во время разработки миграции кода, что это необходимо, и, следовательно, кажется, что она подвержена ошибкам.
б. Когда я генерирую агрегированные скрипты, я запускаю их против базы данных с нуля, чтобы доказать их, и в итоге я вручную вводил инструкции "GO", где это необходимо, в script. Это раздражающий процесс, который нужно возвращать и делать, а результат - Script, который не является 100% -ным отражением мигрирования кода.
Я не потратил много времени на копание исходного кода EF Code Migrations еще, чтобы узнать, могу ли я понять, почему он интерпретирует "GO" как хранимую процедуру, и есть ли что-либо в исходном коде, который указывает на способ предоставить директиву, которая позволила бы избежать этого.
Ответ 3
В результате я использовал два разных класса Configuration
, когда выполнял миграцию с параметром -Script
и без него. В одном из моих классов Configuration
я переношу его MigrationSqlGenerator
в пользовательскую реализацию, которая добавляет операторы GO
.
Ответ 4
Я использовал:
public class MigrationScriptBuilder : SqlServerMigrationSqlGenerator
{
#if !DEBUG
protected override void Generate(System.Data.Entity.Migrations.Model.SqlOperation sqlOperation)
{
Statement("GO");
base.Generate(sqlOperation);
Statement("GO");
}
#endif
}
Поэтому, когда он отлаживается, он не падает. И я script из режима выпуска.
Ответ 5
Это работает для меня:
public class MigrationScriptBuilder : SqlServerMigrationSqlGenerator
{
public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
{
var statements = base.Generate(migrationOperations, providerManifestToken);
statements = statements.SelectMany(s => new[] {
s,
new MigrationStatement
{
Sql = "GO"
}
}).ToList();
return statements;
}
}
Какой (как видно из других ответов) можно использовать (поток процессов миграции) с помощью такого метода в конфигурации DbContext:
public Configuration()
{
SetSqlGenerator("System.Data.SqlClient", new MigrationScriptBuilder());
}