使用实体框架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在和一些指针的这个问题的答案我找到了一种方法。
下面FO那些有兴趣的细节。
问题
该SqlServerMigrationSqlGenerator
是类最终用于创建开始使用时对目标数据库执行或脚本出来的SQL语句负责-Script
在Package Manager控制台交换机或使用时MigratorScriptingDecorator
。
宋建波
检查中的Genearate方法SqlServerMigrationSqlGenerator
负责一个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);
}
}
你可以看到它一直使用的变量名的轨道,但这个似乎只保留一个批次内的轨道,即单一的迁移 。 因此,如果一个migratin包含多于一个DROP COLUM
上述工作正常,但如果存在两个迁移,这导致一个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");
}
}
现在,以强制迁移到使用自定义生成器,你有两个选择:
如果你希望它被集成到程序包管理器控制台,下面的行添加到您的Configuration
类:
SetSqlGenerator("System.Data.SqlClient", new BatchSqlServerMigrationSqlGenerator());
如果您正在生成的脚本代码(如我),添加的代码,你有你的配置组件代码类似的一行:
migrationsConfiguration.SetSqlGenerator(DataProviderInvariantName, new BatchSqlServerMigrationSqlGenerator());