我如何可以覆盖MigratorScriptingDecorator生成的SQL脚本(How can

2019-09-17 20:50发布

使用实体框架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”语句,以便每个迁移是在一个单独的批处理,这将解决这个问题。

任何人有任何想法如何做到这一点,或者如果我找错了树,那么也许你可以提出一个更好的办法?

Answer 1:

因此,与广泛使用的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");
    }
}

现在,以强制迁移到使用自定义生成器,你有两个选择:

  1. 如果你希望它被集成到程序包管理器控制台,下面的行添加到您的Configuration类:

      SetSqlGenerator("System.Data.SqlClient", new BatchSqlServerMigrationSqlGenerator()); 
  2. 如果您正在生成的脚本代码(如我),添加的代码,你有你的配置组件代码类似的一行:

     migrationsConfiguration.SetSqlGenerator(DataProviderInvariantName, new BatchSqlServerMigrationSqlGenerator()); 


文章来源: How can I override SQL scripts generated by MigratorScriptingDecorator