2012-06-07 6 views
6

Entity Framework 4.3.1コードの最初の使用とデータ移行。MigratorScriptingDecoratorで生成されたSQLスクリプトを無効にする方法

MigratorScriptingDecoratorを使用して、ターゲットデータベースの移行スクリプトを自動的に生成するユーティリティを作成しました。

ただし、ターゲットデータベースを最初から再生成する場合、同じ名前の変数を2回宣言するという点で、生成されたスクリプトは無効です。

変数名は@ var0です。

これは、複数の移行が適用されている場合、および少なくとも2つのデフォルト制約が破棄された場合に発生します。

問題は、両方の発生スクリプト形式のコードを生成する際に、パッケージマネージャコンソール・コマンドを使用する場合:

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

:ここ

Update-Database -Script 

を問題の断片が生成されたスクリプトを形成しています

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に広範囲に使用すると、私は方法を見つけました。

興味のある人のための詳細。

SqlServerMigrationSqlGenerator問題MigratorScriptingDecoratorを使用した場合、パッケージマネージャコンソールで-Scriptスイッチを使用する場合、またはターゲット・データベースに対して実行またはスクリプト出力を取得するSQL文を作成するための最終的な責任を負うクラスです。 DROP COLUMNする責任があるSqlServerMigrationSqlGeneratorでGenearate方法を調べる

のWorkings

、それは次のようになります。

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); 
    } 
} 

あなたはそれが使用されている変数名を追跡して見ることができますが、 これは、バッチ内での追跡、つまり1回の移行のように見えるだけです。したがって、migratinに複数のDROP COLUMが含まれている場合、上記はうまくいきますが、DROP COLUMNという2つのマイグレーションがあると、_variableCounter変数がリセットされます。

スクリプトを生成しないときは、各ステートメントがデータベースに対して直ちに実行されるため、問題は発生しません(SQLプロファイラを使用して確認しました)。

SQLスクリプトを生成していて、問題があるもののそのまま実行したい場合。

ソリューション

次のように私は(あなたがusing System.Data.Entity.Migrations.Sql;が必要に注意してください)SqlServerMigrationSqlGeneratorから継承新しいBatchSqlServerMigrationSqlGeneratorを作成しました:

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

     Statement("GO"); 
    } 
} 

今、あなたは2つのオプションがあり、カスタム・ジェネレータを使用するように移行を強制します:

  1. tに統合したい場合彼パッケージマネージャコンソールは、あなたのConfigurationクラスに以下の行を追加します。

    SetSqlGenerator("System.Data.SqlClient", 
            new BatchSqlServerMigrationSqlGenerator()); 
    
  2. をあなたは(私がしたような)コードからスクリプトを生成している場合、あなたが設定アセンブリ持ってどこにコードのような行を追加しますコード内で:

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

あなたが同様の問題を回避するには、通常、直接テーブルの挿入のために生成されるSQLは可能かもしれないと思いますか? –

関連する問題