首先使用Entity Framework 4.3.1代码和数据迁移。
我编写了一个实用程序,使用MigratorScriptingDecorator为目标数据库自动生成迁移脚本。
但是,有时从头开始重新生成目标数据库时,生成的脚本无效,因为它声明了两次具有相同名称的变量。
变量名称为 @ var0 。
当应用多个迁移时,以及当至少两个迁移导致默认约束被删除时,似乎会发生这种情况。
在生成脚本表单代码和使用Package Manager控制台命令时都会出现问题:
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”语句,以便每次迁移都在一个单独的批处理中,这将解决问题。
任何人都有任何想法如何做到这一点,或者如果我咆哮错误的树然后你可以建议一个更好的方法?
答案 0 :(得分:4)
因此,在ILSpy中广泛使用了the answer to this question和一些指针,我找到了一种方法。
以下是有兴趣的人的详细信息。
<强>问题强>
SqlServerMigrationSqlGenerator
是最终负责创建对目标数据库执行的SQL语句或在Package Manager控制台中使用-Script
开关时使用{{1 }}
<强>巷道强>
检查负责MigratorScriptingDecorator
的{{1}}中的Genearate方法,它看起来像这样:
SqlServerMigrationSqlGenerator
您可以看到它跟踪所使用的变量名称,但这似乎只能在批次中跟踪,即单次迁移。因此,如果一个migratin包含多个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
变量。
不生成脚本时不会遇到任何问题,因为每个语句都是针对数据库立即执行的(我使用SQL事件探查器检查过)。
如果您生成了一个SQL脚本,并希望尽管遇到问题仍然按原样运行它。
<强>解决方案强>
我创建了一个新的DROP COLUMN
,继承自_variableCounter
,如下所示(请注意,您需要BatchSqlServerMigrationSqlGenerator
):
SqlServerMigrationSqlGenerator
现在要强制迁移使用自定义生成器,您有两个选择:
如果您希望将其集成到Package Manager控制台中,请将以下行添加到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