そのため、この質問への回答でILSpyといくつかのポインターを広範に使用することで、方法を見つけました。
興味のある方は以下詳細を。
問題
はSqlServerMigrationSqlGenerator
、ターゲット データベースに対して実行される SQL ステートメントの作成、または-Script
パッケージ マネージャー コンソールでスイッチを使用する場合、またはMigratorScriptingDecorator
.
仕組み
SqlServerMigrationSqlGenerator
を担当する の Genearate メソッドを調べると、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);
}
}
使用されている変数名を追跡していることがわかりますが、これはバッチ内、つまり単一の migration 内で追跡しているように見えます。そのため、移行に複数のものが含まれている場合DROP COLUM
、上記は正常に機能しますが、2 つの移行DROP COLUMN
が生成される結果になる場合、_variableCounter
変数はリセットされます。
各ステートメントはデータベースに対してすぐに実行されるため、スクリプトを生成しない場合は問題は発生しません (SQL プロファイラーを使用して確認しました)。
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");
}
}
移行でカスタム ジェネレーターを使用するように強制するには、次の 2 つのオプションがあります。
パッケージ マネージャー コンソールに統合する場合は、以下の行をConfiguration
クラスに追加します。
SetSqlGenerator("System.Data.SqlClient",
new BatchSqlServerMigrationSqlGenerator());
コードからスクリプトを生成している場合 (私のように)、同様のコード行をコード内の構成アセンブリがある場所に追加します。
migrationsConfiguration.SetSqlGenerator(DataProviderInvariantName,
new BatchSqlServerMigrationSqlGenerator());