【问题标题】:Using Entity Framework 6, Custom Code-First Migrations & CSharpMigrationCodeGenerator使用 Entity Framework 6、自定义代码优先迁移和 CSharpMigrationCodeGenerator
【发布时间】:2015-11-30 18:47:16
【问题描述】:

我最近开始使用 Entity Framework 6 的代码优先自定义迁移。它运行良好,但我想做的一件事是在尝试重命名索引时生成一对CreateIndex()DropIndex() 语句,而不是像默认的CSharpMigrationCodeGenerator 那样使用RenameIndex()

例如,我目前在流畅映射中使用数据注释来重命名索引,如下所示:

Property(x => x.TeacherId).HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_Students_TeacherId")));

这里的问题是,默认情况下,EF6 希望在我添加新迁移以捕获对模型的此更改时生成以下代码:

using System;
using System.Data.Entity.Migrations;

namespace MyApp.Migrations
{
    public partial class RenameIndexTest : DbMigration
    {
        public override void Up()
        {
            // BAD: [RenameIndex] will generate a "EXEC sp_rename" statement.
            RenameIndex(table: "dbo.Students", name: "IX_TeacherId", newName: "IX_Students_TeacherId");
        }

        public override void Down()
        {
            RenameIndex(table: "dbo.Students", name: "IX_Students_TeacherId", newName: "IX_TeacherId");
        }
    }
}

但我真正需要 EF6 生成的是:

using System;
using System.Data.Entity.Migrations;

namespace MyApp.Migrations
{
    public partial class RenameIndexTest : DbMigration
    {
        public override void Up()
        {
            // GOOD: We generate separate SQL statements to drop & add the index.
            DropIndex(table: "dbo.Students", name: "IX_TeacherId");
            CreateIndex(table: "dbo.Students", name: "IX_Students_TeacherId", column: "TeacherId");
        }

        public override void Down()
        {
            DropIndex(table: "dbo.Students", name: "IX_Students_TeacherId");
            CreateIndex(table: "dbo.Students", name: "IX_TeacherId", column: "TeacherId");
        }
    }
}

我们的数据团队有一个硬性要求,即开发人员在重命名索引时使用 T-SQL DROP/CREATE 语句。到目前为止,我还没有找到一种方法来覆盖RenameIndex() 语句的行为,使用使用CSharpMigrationCodeGenerator 作为其基类的自定义类,因为RenameIndexOperation 类没有任何信息关于已在其上创建索引的列。

这是我自己能够做到的:

namespace MyApp.Migrations
{
    internal class CustomCSharpMigrationCodeGenerator : CSharpMigrationCodeGenerator
    {
        protected override string Generate(IEnumerable<MigrationOperation> operations, string @namespace, string className)
        {
            var customizedOperations = new List<MigrationOperation>();

            foreach (var operation in operations)
            {
                if (operation is RenameIndexOperation)
                {
                    var renameIndexOperation = operation as RenameIndexOperation;

                    var dropIndexOperation = new DropIndexOperation(operation.AnonymousArguments)
                    {
                        Table = renameIndexOperation.Table,
                        Name = renameIndexOperation.Name
                    };

                    var createIndexOperation = new CreateIndexOperation(operation.AnonymousArguments)
                    {
                        Table = renameIndexOperation.Table,
                        Name = renameIndexOperation.NewName,

                        // HELP: How do I get this information about the existing index?
                        // HELP: How do I specify what columns the index should be created on?
                        IsUnique = false,
                        IsClustered = false
                    };

                    // Do not generate a RenameIndex() statement; instead, generate a pair of DropIndex() and CreateIndex() statements.
                    customizedOperations.Add(dropIndexOperation);
                    customizedOperations.Add(createIndexOperation);
                }
                else
                {
                    customizedOperations.Add(operation);
                }
            }

            return base.Generate(customizedOperations, @namespace, className);
        }
    }
}

这有意义吗?更重要的是,是否有人对如何进行有任何建议或想法?不管怎样,提前致谢!

【问题讨论】:

  • 您可以使用自定义 SqlServerMigrationSqlGenerator 来接近它。见romiller.com/2012/01/16/… 可以拦截 CreateIndexOperation() 并编写自己的 SQL。另请参阅stackoverflow.com/questions/8594431/…
  • 我试图拦截RenameIndexOperation,而不是CreateIndexOperation。在我添加迁移以正确设置它之前,该索引已经存在。另外,CreateIndexOperation inherits from IndexOperation,它公开了我需要的 Columns 属性。但是,RenameIndexOperation inherits from MigrationOperation,它不会公开它。
  • @SteveGreene:对不起,我上面的空间用完了。基本上,我需要一种方法将RenameIndexOperation 重写为一对DropIndexOperationCreateIndexOperation 操作。简单地拦截我的CreateIndexOperation 是行不通的。
  • @SteveGreene:这正是我在原始帖子中所说的......我的最后一个代码 sn-p 甚至说明了我是如何无法做到这一点的。
  • 如果您从 Up() 代码中将其添加为匿名参数,它将获得该信息,但有人可能会争辩说您不妨只使用 Sql("DROP INDEX ...");和 Sql("CREATE INDEX ...");

标签: entity-framework entity-framework-6 entity-framework-migrations


【解决方案1】:

我要结束这个问题了。我从来没有能够完全按照我的要求去做......这不是破坏交易,我只是希望 EF6 有某种方式(轻松)对正在创建的索引的名称施加控制。

IIRC,我按照 @steve-greene 的建议做了,并使用 Sql() 方法手动指定了索引的名称。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-04
    • 1970-01-01
    • 2020-04-29
    • 2016-11-03
    • 2018-07-02
    • 1970-01-01
    • 2014-01-20
    相关资源
    最近更新 更多