17

作为规划实体框架迁移的一部分,为了调试数据移动,我经常使用 -Script 参数来生成脚本。

然后我可以将此脚本带到查询分析器并将其包装在事务中以便手动测试它。

我遇到了一种情况,我们需要一个 Go 语句来正确执行脚本。为了在适当的位置输出 Go,将以下代码添加到迁移中。

Sql("GO");

当使用 -Script 时,这会在适当的位置添加一个 GO 语句。但是当不使用 -Script 时。我得到了例外...

System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'.

有没有一种安全的方法可以将 Go 命令添加到脚本中?

4

5 回答 5

15

我最近遇到了完全相同的情况。我的 EF 代码迁移经常引入一个新的表或列,然后我还将使用 Sql(...) 的数据迁移放入那些有时想要引用新表/列的迁移中。正如您所指出的,当作为 EF 代码迁移运行时,每个语句似乎都作为离散批处理发布到数据库,因此没有任何问题。但是,为了满足生产部署的限制,我们将一组代码从 sprint 迁移到单个脚本(使用 -Script),以便为部署团队提供单个聚合 SQL 脚本迁移。正如您所指出的,此脚本文件有时会失败,因为它尝试从单个代码迁移中处理单个 T SQL 批处理,其中后面的语句尝试引用仅在批处理中较早定义的结构。

我并不特别喜欢我现在为减轻这种情况而采取的两种方法中的任何一种,但它们是:

一个。如果我当时碰巧在考虑,我会将代码迁移分成两个迁移,这样在编写脚本时,它们会分成两个(或更多)单独的批次。我不喜欢这样,因为在代码迁移的开发过程中没有任何反馈表明这是必要的,因此它似乎容易出错。

湾。当我生成聚合脚本时,我针对一个临时数据库运行它们以证明它们,并且我最终在该脚本中必要的地方手动注入“GO”语句。这是一个令人讨厌的过程,必须返回并执行,并导致 -Script 输出不是代码迁移的 100% 反映。

我还没有花太多时间深入研究 EF Code Migrations 的源代码,看看我是否能理解为什么它将“GO”解释为存储过程,以及源代码中是否有任何东西可以指向一种方法提供一个可以避免这种情况的指令。

于 2012-09-19T12:51:17.430 回答
9
internal sealed class Configuration : DbMigrationsConfiguration<Context>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
        const string providerInvariantName = "System.Data.SqlClient";
        SetSqlGenerator(providerInvariantName, new BatchingMigrationSqlGenerator(GetSqlGenerator(providerInvariantName)));
    }

    protected override void Seed(Context context)
    {
    }

}

internal class BatchingMigrationSqlGenerator : MigrationSqlGenerator
{
    private readonly MigrationSqlGenerator migrationSqlGenerator;

    public BatchingMigrationSqlGenerator(MigrationSqlGenerator migrationSqlGenerator)
    {
        this.migrationSqlGenerator = migrationSqlGenerator;
    }

    public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
    {
        var migrationStatements = migrationSqlGenerator.Generate(migrationOperations, providerManifestToken).ToArray();
        foreach (var migrationStatement in migrationStatements)
        {
            migrationStatement.BatchTerminator = "GO";
        }
        return migrationStatements;
    }
}
于 2015-07-02T10:10:06.840 回答
2

Configuration当我使用和不使用-Script参数运行迁移时,我最终使用了两个不同的类。在我的一个Configuration类中,我将其包装MigrationSqlGenerator在一个自定义实现中,该实现添加了GO语句。

于 2013-02-14T07:41:56.893 回答
0

这对我有用:

public class MigrationScriptBuilder : SqlServerMigrationSqlGenerator
{
    public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
    {
        var statements = base.Generate(migrationOperations, providerManifestToken);

        statements = statements.SelectMany(s => new[] {
            s,
            new MigrationStatement
            {
                Sql = "GO"
            }
        }).ToList();

        return statements;
    }
}

在 DbContext 配置中,可以通过这种方法使用哪个(如其他答案所示)(迁移流程):

    public Configuration()
    {
        SetSqlGenerator("System.Data.SqlClient", new MigrationScriptBuilder());
    }
于 2017-08-31T06:10:21.500 回答
0

我用过:

public class MigrationScriptBuilder : SqlServerMigrationSqlGenerator
{
#if !DEBUG
    protected override void Generate(System.Data.Entity.Migrations.Model.SqlOperation sqlOperation)
    {
        Statement("GO");

        base.Generate(sqlOperation);

        Statement("GO");
    }
#endif
}

所以当它调试时它不会崩溃。我从发布模式编写脚本。

于 2015-11-20T12:35:40.233 回答