18

所以我有一个应用程序,其中包含由 Entity 框架进行的大量迁移。我们希望一次为所有迁移获取一个脚本,并且使用该-Script标签确实可以正常工作。

但是......它不会GO在 SQL 中添加语句,给我们带来类似的问题Alter view should be the first statement in a batch file...

我一直在搜索并手动添加Sql("GO");有关此问题的帮助,但针对整个脚本。当我再次使用包控制台管理器时,它会返回一个异常。

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

有没有办法在使用标签时添加这些GO标签?如果没有,有什么好的方法呢?-Script

注意:我们也尝试过拥有多个文件,但由于我们有如此多的迁移,这几乎不可能每次都维护。

4

5 回答 5

19

如果您尝试使用 更改视图Sql("Alter View dbo.Foos As etc"),则可以通过将 sql 放入命令中来避免should be the first statement in a batch file错误而无需添加语句:GOEXEC

Sql("EXEC('Alter View dbo.Foos As etc')")

于 2013-12-03T13:46:21.033 回答
12

为了更改实体框架迁移生成的 SQL,您可以创建一个新的SqlServerMigrationSqlGenerator

我们这样做是为了在迁移历史之前和之后添加一个 GO 语句:

public  class MigrationScriptBuilder: SqlServerMigrationSqlGenerator
{
    protected override void Generate(System.Data.Entity.Migrations.Model.InsertHistoryOperation insertHistoryOperation)
    {
        Statement("GO");

        base.Generate(insertHistoryOperation);

        Statement("GO");

    }
}

然后添加Configuration构造函数(在 MigrationsDbContext 所在的项目文件夹中),以便它使用这个新的 sql 生成器:

[...]
internal sealed class Configuration : DbMigrationsConfiguration<PMA.Dal.PmaContext>
{
    public Configuration()
    {
        SetSqlGenerator("System.Data.SqlClient", new MigrationScriptBuilder());
        AutomaticMigrationsEnabled = false;
    }
[...]

insert into [__MigrationHistory]因此,现在当您使用-Script标签生成脚本时,您可以看到GO

或者,在您的实施中,SqlServerMigrationSqlGenerator您可以覆盖脚本生成的任何部分,这InsertHistoryOperation适合我们。

于 2013-06-14T11:35:55.497 回答
10

原来这个概念SqlServerMigrationSqlGenerator作为可选参数存在于Statement(sql, batchTerminator). 这是基于 Skype 想法的东西。它在 -script 模式下都可以工作。GO 用于与 Skype 不同的操作,只是因为我们的需求略有不同。然后,您需要Configuration按照 Skype 说明注册此类。

    public class MigrationScriptBuilder : SqlServerMigrationSqlGenerator
    {
        private string Marker = Guid.NewGuid().ToString(); //To cheat on the check null or empty of the base generator

        protected override void Generate(AlterProcedureOperation alterProcedureOperation)
        {
            SqlGo();
            base.Generate(alterProcedureOperation);
            SqlGo();
        }
        protected override void Generate(CreateProcedureOperation createProcedureOperation)
        {
            SqlGo();
            base.Generate(createProcedureOperation);
            SqlGo();
        }
        protected override void Generate(SqlOperation sqlOperation)
        {
            SqlGo();
            base.Generate(sqlOperation);
        }

        private void SqlGo()
        {
            Statement(Marker, batchTerminator: "GO");
        }

        public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
        {
            var result = new List<MigrationStatement>();
            var statements = base.Generate(migrationOperations, providerManifestToken);

            bool pendingBatchTerminator = false;
            foreach (var item in statements)
            {
                if(item.Sql == Marker && item.BatchTerminator == "GO")
                {
                    pendingBatchTerminator = true;
                }
                else
                {
                    if(pendingBatchTerminator)
                    {
                        item.BatchTerminator = "GO";
                        pendingBatchTerminator = false;
                    }
                    result.Add(item);
                }
            }

            return result;
        }
    }
于 2016-11-14T22:04:23.637 回答
2

最简单的方法是在 GO 语句之前添加 /**/。

于 2019-12-24T16:10:15.387 回答
-3

只需将当前语句替换为 .Replace("GO", "");

于 2015-01-23T13:50:16.383 回答