使用 Entity Framework 6.1 fluent API 创建唯一索引
Posted
技术标签:
【中文标题】使用 Entity Framework 6.1 fluent API 创建唯一索引【英文标题】:Creating Unique Index with Entity Framework 6.1 fluent API 【发布时间】:2014-07-16 13:13:48 【问题描述】:我有一列“名称”必须是唯一的。没有外键或类似的东西。
EF 6.1 最终支持通过注释创建此类索引。这已经在 SO 上讨论过了。但似乎只能通过类中的注释来完成。如何仅使用 Fluent API 做到这一点?
类似这样的:
public class PersonConfiguration : EntityTypeConfiguration<Person>
public PersonConfiguration()
HasKey(p => p.Id);
Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
//not possible?
Index(p => p.Name).IsUnique(); //???
【问题讨论】:
【参考方案1】:注意:与 EF 6 相关
如前所述,您可以使用IndexAttribute
,但可以使用with Fluent API
而不是DataAnnotations
,这样可以解决问题:
modelBuilder
.Entity<Person>()
.Property(t => t.Name)
.HasColumnAnnotation(
"Index",
new IndexAnnotation(new IndexAttribute("IX_Name") IsUnique = true ));
不幸的是,没有其他方法可以使用Fluent API
创建唯一索引。关于此功能有一个未解决的问题:Unique Constraints (Unique Indexes)
更新:实体框架核心 在最新的 EF Core 版本中,您可以依赖
Fluent API
to specify indexes 而无需额外的技巧。
HasIndex
允许定义它:
modelBuilder
.Entity<Person>()
.HasIndex(x => x.Name);
因此它返回IndexBuilder
对象,您可以将其用于进一步的索引配置(即唯一性):
modelBuilder
.Entity<Person>()
.HasIndex(x => x.Name)
.IsUnique();
【讨论】:
这就是我要找的。不像希望的那么简单,但它确实有效。谢谢。【参考方案2】:根据 Anatolii 的回答,这里有一个更流畅地设置唯一索引的扩展方法:
public static class MappingExtensions
public static PrimitivePropertyConfiguration IsUnique(this PrimitivePropertyConfiguration configuration)
return configuration.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute IsUnique = true ));
用法:
modelBuilder
.Entity<Person>()
.Property(t => t.Name)
.IsUnique();
会产生迁移如:
public partial class Add_unique_index : DbMigration
public override void Up()
CreateIndex("dbo.Person", "Name", unique: true);
public override void Down()
DropIndex("dbo.Person", new[] "Name" );
【讨论】:
是否可以保持流畅的链,或者 IsUnique() 必须是最后一个?此外,对于自定义约定,您可以将相同的方法用于ConventionPrimitivePropertyConfiguration
而不是 PrimitivePropertyConfiguration
类型。
流畅链可以用StringPropertyConfiguration
维护。【参考方案3】:
此答案仅包含附加信息,因为已经有很好的答案。
如果您想在索引中拥有多个唯一字段,可以通过添加Order
属性来实现。您还必须确保在所有属性中使用相同的索引名称(请参阅下面的 uniqueIndex
)。
string uniqueIndex = "UN_TableName";
this.Property(t => t.PropertyOne)
.HasColumnAnnotation(
IndexAnnotation.AnnotationName,
new IndexAnnotation(
new IndexAttribute(uniqueIndex)
IsUnique = true,
Order = 1
)
);
this.Property(t => t.PropertyTwo)
.HasColumnAnnotation(
IndexAnnotation.AnnotationName,
new IndexAnnotation(
new IndexAttribute(uniqueIndex)
IsUnique = true,
Order = 2
)
);
现在,假设您还想在PropertyTwo
上建立索引。
错误的做法是用this.Property(t => t.PropertyTwo)
开始一个新行,因为它会取消你的唯一索引。
必须同时定义所有索引(索引和唯一索引)。这将是正确的方法:
this.Property(t => t.PropertyTwo)
.HasColumnAnnotation(
IndexAnnotation.AnnotationName,
new IndexAnnotation(new[]
new IndexAttribute(), // This is the index
new IndexAttribute(uniqueIndex) // This is the Unique made earlier
IsUnique = true,
Order = 2
)
);
最后,如果你还想改变你的索引/唯一的排序顺序,你可以看到:
How to add an index on multiple columns with ASC/DESC sort using the Fluent API ?.
【讨论】:
现在 ASC/DESC 排序可用于 6.2 吗?还有你的第二个例子,如何在 6.2 中使用 HasIndex 方法?【参考方案4】:在6.2的新版EF中可以使用HasIndex
方法:
modelBuilder.Entity<User>().HasIndex(user => user.Email).IsUnique(true);
modelBuilder.Entity<User>().HasIndex(user => user.UserName).IsUnique(true);
EF Core 更新:
modelBuilder.Entity<User>()
.HasIndex(b => b.Email)
.IsUnique();
modelBuilder.Entity<User>()
.HasIndex(b => b.UserName)
.IsUnique();
Microsoft Docs - EF Core Indexes
【讨论】:
【参考方案5】:您可以在迁移文件中创建唯一索引。
在包管理器中:
-
启用迁移
添加迁移初始迁移
这将在您的 Migrations 文件夹中创建一个带有时间戳的新文件。该类将有一个 Up 和 Down 方法,您可以使用它们来创建索引:
public override void Up()
// ...
CreateIndex("tableName", "columnName", unique: true, name: "myIndex");
public override void Down()
// ...
DropIndex("tableName", "myIndex");
在包管理器中运行迁移类型更新数据库。
您还可以在创建表的迁移过程中添加索引:
CreateTable(
"dbo.Products",
c => new
ProductId = c.Int(nullable: false, identity: true),
ProductName = c.String(nullable: false, maxLength: 256),
)
.Index(c => c.ProductName, name: "IX_Products_ProductName", unique: true)
.PrimaryKey(t => t.ProductId);
【讨论】:
【参考方案6】:对我来说,使用 MVC 5 和 EF 6,关键点是在我想要放置索引的字符串属性上指定一个长度。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
//More stuff
modelBuilder.Entity<Device>().Property(c => c.Name).HasColumnType("nvarchar").HasMaxLength(50);
modelBuilder.Entity<Device>().HasIndex(c => c.Name).IsUnique(true);
【讨论】:
以上是关于使用 Entity Framework 6.1 fluent API 创建唯一索引的主要内容,如果未能解决你的问题,请参考以下文章
使用 Entity Framework 6.1 和 MVC 5 从数据库中使用 Code First 后如何同步模型?
如何在 Entity Framework 6.1 中仅加载子对象的某些字段?
如何将针对 Entity Framework .Net 4.6.1 的库与 .Net Core 应用程序一起使用