【发布时间】: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。在我添加迁移以正确设置它之前,该索引已经存在。另外,CreateIndexOperationinherits fromIndexOperation,它公开了我需要的 Columns 属性。但是,RenameIndexOperation inherits from MigrationOperation,它不会公开它。 -
@SteveGreene:对不起,我上面的空间用完了。基本上,我需要一种方法将
RenameIndexOperation重写为一对DropIndexOperation和CreateIndexOperation操作。简单地拦截我的CreateIndexOperation是行不通的。 -
@SteveGreene:这正是我在原始帖子中所说的......我的最后一个代码 sn-p 甚至说明了我是如何无法做到这一点的。
-
如果您从 Up() 代码中将其添加为匿名参数,它将获得该信息,但有人可能会争辩说您不妨只使用 Sql("DROP INDEX ...");和 Sql("CREATE INDEX ...");
标签: entity-framework entity-framework-6 entity-framework-migrations