使用 Entity Framework 6、自定义代码优先迁移和 CSharpMigrationCodeGenerator
Using Entity Framework 6, Custom Code-First Migrations & CSharpMigrationCodeGenerator
我最近开始使用 Entity Framework 6 的代码优先自定义迁移。它运行良好,但我想做的一件事是在尝试重命名索引时生成一对 CreateIndex()
和 DropIndex()
语句,而不是像默认 CSharpMigrationCodeGenerator
想。
例如,我目前在流式映射中使用数据注释来重命名索引,如下所示:
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
作为其基础 class 的自定义 class,因为 RenameIndexOperation
class 没有关于在其上创建索引的列的任何信息。
这是我自己所能做到的:
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);
}
}
}
这有意义吗?更重要的是,有人对如何进行有任何建议或想法吗?无论哪种方式,提前致谢!
我正在关闭这个问题。我永远无法完全按照我的意愿去做...这不是一个破坏者,我只是希望 EF6 有某种方式(轻松地)对正在创建的索引的名称施加控制。
IIRC,我按照 @steve-greene 的建议做了,并使用 Sql()
方法手动指定了索引的名称。
我最近开始使用 Entity Framework 6 的代码优先自定义迁移。它运行良好,但我想做的一件事是在尝试重命名索引时生成一对 CreateIndex()
和 DropIndex()
语句,而不是像默认 CSharpMigrationCodeGenerator
想。
例如,我目前在流式映射中使用数据注释来重命名索引,如下所示:
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
作为其基础 class 的自定义 class,因为 RenameIndexOperation
class 没有关于在其上创建索引的列的任何信息。
这是我自己所能做到的:
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);
}
}
}
这有意义吗?更重要的是,有人对如何进行有任何建议或想法吗?无论哪种方式,提前致谢!
我正在关闭这个问题。我永远无法完全按照我的意愿去做...这不是一个破坏者,我只是希望 EF6 有某种方式(轻松地)对正在创建的索引的名称施加控制。
IIRC,我按照 @steve-greene 的建议做了,并使用 Sql()
方法手动指定了索引的名称。