【问题标题】:Creating Unique Index with Entity Framework 6.1 fluent API使用 Entity Framework 6.1 fluent API 创建唯一索引
【发布时间】:2023-03-20 20:33:01
【问题描述】:

我有一列“名称”必须是唯一的。没有外键或类似的东西。

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();  //???
    }
}

【问题讨论】:

    标签: c# .net entity-framework entity-framework-6 fluent-interface


    【解决方案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】:

      您可以在迁移文件中创建唯一索引。

      在包管理器中:

      1. 启用迁移
      2. 添加迁移初始迁移

      这将在您的 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); 
        }
        

        【讨论】:

          猜你喜欢
          • 2014-03-28
          • 2014-09-05
          • 2018-02-08
          • 1970-01-01
          • 2012-01-05
          • 2014-02-07
          • 2014-09-11
          • 2013-08-16
          • 1970-01-01
          相关资源
          最近更新 更多