首先使用实体框架 4.3.1 代码和数据迁移。
我编写了一个实用程序来使用 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”语句,以便每个迁移都在一个单独的批处理中,这将解决问题。
任何人都有任何想法如何做到这一点,或者如果我在错误的树上吠叫,那么也许您可以提出更好的方法?
最佳答案
所以随着ILSpy的广泛使用以及 the answer to this question 中的一些指针我找到了一个方法。
有兴趣的可以往下看。
问题 SqlServerMigrationSqlGenerator
是最终负责创建 SQL 语句的类,这些 SQL 语句在使用 -Script
时针对目标数据库执行或编写脚本。在包管理器控制台或使用 MigratorScriptingDecorator
时切换.
作品
检查 SqlServerMigrationSqlGenerator
中的 Generate 方法负责 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
类(class): SetSqlGenerator("System.Data.SqlClient",
new BatchSqlServerMigrationSqlGenerator());
migrationsConfiguration.SetSqlGenerator(DataProviderInvariantName,
new BatchSqlServerMigrationSqlGenerator());
关于entity-framework - 如何覆盖 MigratorScriptingDecorator 生成的 SQL 脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10930259/