因此,通过广泛使用ILSpy和在这个问题的答案中的一些指示,我找到了一种方法。
有兴趣的人在下面详细说明。
问题
该类SqlServerMigrationSqlGenerator
最终负责创建 SQL 语句,这些语句在使用-Script
包管理器控制台中的开关或使用MigratorScriptingDecorator
.
工作
SqlServerMigrationSqlGenerator
检查负责 a的 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);
}
}
您可以看到它跟踪使用的变量名称,但这似乎只在批次内跟踪,即单个迁移。因此,如果一个迁移包含多个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");
}
}
现在要强制迁移使用您的自定义生成器,您有两个选择:
如果您希望将其集成到包管理器控制台中,请将以下行添加到您的Configuration
类中:
SetSqlGenerator("System.Data.SqlClient",
new BatchSqlServerMigrationSqlGenerator());
如果您是从代码生成脚本(就像我一样),请在代码中添加配置程序集的位置添加类似的代码行:
migrationsConfiguration.SetSqlGenerator(DataProviderInvariantName,
new BatchSqlServerMigrationSqlGenerator());