使用 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 =&gt; 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 应用程序一起使用

linq to sql 鍜?entity framework 杈撳嚭sql璇彞

Entity Framework 和 Sqlite

Entity Framework 和 Sqlite