2012-06-07 2 views
6

Использование Entity Framework 4.3.1 Сначала код и миграция данных.Как я могу переопределить SQL-скрипты, сгенерированные MigratorScriptingDecorator

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

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

Имя переменной @ var0.

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

Проблема возникает как при генерации скрипта код формы, и при использовании команды консоли Диспетчер пакетов:

Update-Database -Script 

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

DECLARE @var0 nvarchar(128) 
SELECT @var0 = name 
FROM sys.default_constraints 
WHERE parent_object_id = object_id(N'SomeTableName') 

и

DECLARE @var0 nvarchar(128) 
SELECT @var0 = name 
FROM sys.default_constraints 
WHERE parent_object_id = object_id(N'SomeOtherTableName') 

Я хотел бы иметь возможность переопределить точку, где она связывает SQL для каждой миграции, а затем добавляет оператор «GO», чтобы каждая миграция была в отдельной партии, что бы решить проблему.

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

ответ

4

Так что при широком использовании ILSpy и некоторых указателей в the answer to this question Я нашел способ.

Информация ниже для заинтересованных.

Проблема

The SqlServerMigrationSqlGenerator класс, в конечном счете отвечает за создание операторов SQL, которые получают исполненные против целевой базы данных или скриптовых, когда с помощью -Script переключателя в консоли диспетчера пакетов или при использовании MigratorScriptingDecorator.

Разработки

экспертизы метод Genearate в SqlServerMigrationSqlGenerator, который отвечает за DROP COLUMN, это выглядит следующим образом:

protected virtual void Generate(DropColumnOperation dropColumnOperation) 
{ 
    RuntimeFailureMethods 
     .Requires(dropColumnOperation != null, null, "dropColumnOperation != null"); 
    using (IndentedTextWriter indentedTextWriter = 
     SqlServerMigrationSqlGenerator.Writer()) 
    { 
     string value = "@var" + this._variableCounter++; 
     indentedTextWriter.Write("DECLARE "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(" nvarchar(128)"); 
     indentedTextWriter.Write("SELECT "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(" = name"); 
     indentedTextWriter.WriteLine("FROM sys.default_constraints"); 
     indentedTextWriter.Write("WHERE parent_object_id = object_id(N'"); 
     indentedTextWriter.Write(dropColumnOperation.Table); 
     indentedTextWriter.WriteLine("')"); 
     indentedTextWriter.Write("AND col_name(parent_object_id, 
                 parent_column_id) = '"); 
     indentedTextWriter.Write(dropColumnOperation.Name); 
     indentedTextWriter.WriteLine("';"); 
     indentedTextWriter.Write("IF "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(" IS NOT NULL"); 
     indentedTextWriter.Indent++; 
     indentedTextWriter.Write("EXECUTE('ALTER TABLE "); 
     indentedTextWriter.Write(this.Name(dropColumnOperation.Table)); 
     indentedTextWriter.Write(" DROP CONSTRAINT ' + "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(")"); 
     indentedTextWriter.Indent--; 
     indentedTextWriter.Write("ALTER TABLE "); 
     indentedTextWriter.Write(this.Name(dropColumnOperation.Table)); 
     indentedTextWriter.Write(" DROP COLUMN "); 
     indentedTextWriter.Write(this.Quote(dropColumnOperation.Name)); 
     this.Statement(indentedTextWriter); 
    } 
} 

Вы можете видеть, что сохраняет имена переменных, используемых, но это только отслеживание в пределах партии, то есть одно перемещение. Поэтому, если мигратин содержит более одного DROP COLUM, это работает отлично, но если есть две миграции, которые приводят к генерации DROP COLUMN, тогда сбрасывается _variableCounter.

При возникновении сценария не возникает никаких проблем, так как каждый оператор выполняется непосредственно против базы данных (я проверил с использованием SQL Profiler).

Если вы создаете SQL-скрипт и хотите запустить его как есть, хотя у вас есть проблема.

Решение

Я создал новый BatchSqlServerMigrationSqlGenerator наследующий SqlServerMigrationSqlGenerator следующим образом (обратите внимание, что вам нужно using System.Data.Entity.Migrations.Sql;):

public class BatchSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator 
{ 
    protected override void Generate 
     (System.Data.Entity.Migrations.Model.DropColumnOperation dropColumnOperation) 
    { 
     base.Generate(dropColumnOperation); 

     Statement("GO"); 
    } 
} 

Теперь, чтобы заставить миграции использовать свой собственный генератор у вас есть два варианта:

  1. Если вы хотите, чтобы он был интегрирован в t он консольный менеджер пакетов, добавьте ниже строку в Configuration класс:

    SetSqlGenerator("System.Data.SqlClient", 
            new BatchSqlServerMigrationSqlGenerator()); 
    
  2. Если вы генерируете скрипт из кода (как я), добавить аналогичную строку кода, где у вас есть сборка конфигурации в коде:

    migrationsConfiguration.SetSqlGenerator(DataProviderInvariantName, 
            new BatchSqlServerMigrationSqlGenerator()); 
    
+0

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

Смежные вопросы