【问题标题】:How to create index in Entity Framework 6.2 with code first如何使用代码在 Entity Framework 6.2 中创建索引
【发布时间】:2014-05-02 07:56:57
【问题描述】:

有没有办法使用代码优先在属性/列上创建索引,而不是使用新的IndexAttribute

【问题讨论】:

  • 索引是数据库概念,不是实体模型概念。即使您可以使用属性或通过 fluent API 指定索引,它实际上也不会在您的应用程序中执行任何操作。它只是 EF 在创建数据库时使用的指令。我相信这些指令属于代码优先迁移,它完全与操作数据库模式有关。

标签: entity-framework entity-framework-6 ef-code-first


【解决方案1】:

2017 年 10 月 26 日,实体框架 6.2 是 officially released。 它包括一个possibility,可通过 Fluent API 轻松定义索引。在 6.2 的 beta 版本中使用的是 announced

现在您可以使用HasIndex() 方法,如果它应该是唯一索引,则可以使用IsUnique()

只是一个小比较(之前/之后)示例:

// before 
modelBuilder.Entity<Person>()
        .Property(e => e.Name)
        .HasColumnAnnotation(
            IndexAnnotation.AnnotationName, 
            new IndexAnnotation(new IndexAttribute { IsUnique = true }));

// after
modelBuilder.Entity<Person>()
    .HasIndex(p => p.Name)
    .IsUnique();

// multi column index
modelBuilder.Entity<Person>()
    .HasIndex(p => new { p.Name, p.Firstname })
    .IsUnique();

也可以使用.IsClustered() 将索引标记为聚簇。


编辑#1

添加了多列索引的示例以及如何将索引标记为聚集的附加信息。


编辑#2

作为附加信息,在 EF Core 2.1 中,它与现在在 EF 6.2 中完全相同。
Here 是作为参考的 MS Doc 文章。

【讨论】:

  • 这太棒了!我想如果我有多列索引,它将类似于: .HasIndex(p => new {p.Name, p.Xyz})
  • 哦,对不起,当然。应该是new。我会解决的。
  • 能否请您展示我们如何在 Core 2.x 中编写相同的代码?
  • 据我所知,它应该与“之后”和“多列索引”下显示的代码相同。
  • 您好,我想使用 Roslyn 部分添加 HasIndex 方法,您能帮忙吗?
【解决方案2】:

目前没有"first class support" 用于通过 fluent API 创建索引,但您可以通过 fluent API 将属性标记为具有来自 Annotation API 的属性。这将允许您通过流畅的界面添加Index 属性。

以下是来自 EF 问题网站的工作项的一些示例。

在单个列上创建索引:

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(new IndexAttribute()));

单个列上的多个索引:

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(new[]
            {
                new IndexAttribute("Index1"),
                new IndexAttribute("Index2") { IsUnique = true }
            }));

多列索引:

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty1)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName,
        new IndexAnnotation(new IndexAttribute("MyIndex", 1)));

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty2)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(new IndexAttribute("MyIndex", 2)));

使用上述技术将导致在您的下一次迁移时在您的 Up() 函数中为您自动创建 .CreateIndex() 调用(如果您不使用迁移,则在数据库中自动创建)。

【讨论】:

  • 可能会在列上添加索引,但不会删除在主键上创建的聚集索引。 hasKey 在默认情况下不会被删除的主键上创建聚集索引。这必须从通过在 .Primarykey(x=&gt;x.id,clustered:false) 方法中声明 clusered:false 创建的迁移文件中显式删除
  • 我试过HasAnnotation方法,没有这样的方法。但我找到了一个名为HasColumnAnnotation 的方法,它接受您提供的参数。你需要更新你的答案还是我错了?
  • @HakamFostok 我直接从 EF 站点获取了示例。可能其中一个版本的名称发生了变化,或者原始版本中存在拼写错误。
  • 请参阅今年早些时候设计会议的以下链接底部的右下方:“将 HasAnnotation 重命名为 HasColumnAnnotation(以及代码库中的其他相关位置)。”。 entityframework.codeplex.com/…
【解决方案3】:

我创建了一些扩展方法并将它们包装在一个 nuget 包中,以使这更容易。

安装EntityFramework.IndexingExtensions nuget 包。

然后您可以执行以下操作:

public class MyDataContext : DbContext
{
  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    modelBuilder.Entity<Customer>()
        .HasIndex("IX_Customers_Name",          // Provide the index name.
            e => e.Property(x => x.LastName),   // Specify at least one column.
            e => e.Property(x => x.FirstName))  // Multiple columns as desired.

        .HasIndex("IX_Customers_EmailAddress",  // Supports fluent chaining for more indexes.
            IndexOptions.Unique,                // Supports flags for unique and clustered.
            e => e.Property(x => x.EmailAddress)); 
  }
}

The project and source code are here。享受吧!

【讨论】:

  • 我真的很喜欢这个包,但是在 up 脚本中搭建脚手架后,索引名称似乎有时会丢失。它仅在我的索引中使用 4 个或更多属性时才出现。我正在使用 EF 6.1.3。
  • @Mixxiphoid - 请您记录问题here 并提供支持详细信息?还要确保您拥有 1.0.1 版本,因为 1.0.0 中有 a bug
  • 我有 1.0.1 版。我将记录该问题,但目前不能这样做。
  • 如何将索引参与列顺序添加到降序?默认情况下 .HasIndex("IX_Customers_EmailAddress", IndexOptions.Unique, ... 为索引中的所有参与列创建升序。
  • @GDroid - 不幸的是,EF 的 IndexAttribute 类没有公开它,所以我不能将它包含在我的库中。
【解决方案4】:

没有明确的名称:

[Index]
public int Rating { get; set; } 

具有特定名称:

[Index("PostRatingIndex")] 
public int Rating { get; set; }

【讨论】:

  • 索引似乎被贬低了:(
  • @HamedZakeryMiab 您使用的是哪个版本的实体框架?索引未被弃用。
  • 对不起,我忘了包括EntityFramework。它包含在该程序集中。只是对 NS 感到困惑。
  • @HamedZakeryMiab 是的,这太令人困惑了!我以为它是 System.DataAnnotations 的一部分!肯定是实体框架包
  • 问题包含以下陈述instead of using the new IndexAttribute你注意到了吗?
【解决方案5】:

从 EF 6.1 开始,支持属性 [Index]
使用 [Index(IsUnique = true)] 作为唯一索引。
这是link from Microsoft

public class User 
{ 
    public int UserId { get; set; } 

    [Index(IsUnique = true)] 
    [StringLength(200)] 
    public string Username { get; set; } 

    public string DisplayName { get; set; } 
}

【讨论】:

  • 虽然这在理论上可以回答问题,it would be preferable 在此处包含答案的基本部分,并提供链接以供参考。
  • @manetsus 很好。我添加了一个代码 sn-p 以反映更改。
  • 字符串长度是必需的,否则您会看到“是一种类型,不能用作索引中的键列”异常。我的同事更喜欢 Conntext 上的 modelBuilder 解决方案,这样您就不会弄乱您的 User 类,我猜这是有效的。
  • 具有多列唯一性的索引呢?拥有多列唯一键索引很常见...
  • @enorl76 这也受支持。对于每一列,您需要使用如下属性,[Index("IX_BlogIdAndRating", 2)]public int Rating { get; set; }[Index("IX_BlogIdAndRating", 1)]public int BlogId { get; set; } 这里是来自Microsoft的参考
【解决方案6】:

实体框架 6

Property(c => c.MyColumn)
        .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_MyIndex")));

并添加使用:

using System.Data.Entity.Infrastructure.Annotations;
using System.ComponentModel.DataAnnotations.Schema;

【讨论】:

    【解决方案7】:

    您可以使用 INDEX 数据注释 Code First Data Annotations

    【讨论】:

    • nvarchar 的最大密钥长度为 900 字节,varchar 的最大密钥长度为 450 字节。如果您首先使用代码,则字符串属性将是 nvarchar 并且您应该包含属性“StringLength”,如 [[StringLength(450)]
    • 从 EF 6.1 开始,这是正确的答案。 docs.microsoft.com/en-us/ef/ef6/modeling/code-first/…
    【解决方案8】:

    如果你不想在你的 POCO 上使用属性,那么你总是可以这样做:

    context.Database.ExecuteSqlCommand("CREATE INDEX IX_NAME ON ..."); 
    

    您可以在自定义的DbInitializer 派生类中执行此语句。不过,我不知道有任何 Fluent API 方法可以做到这一点。

    【讨论】:

    • 当然,Mert。目前我正在使用迁移并且在 Up() 方法中您还可以输入: CreateIndex("dbo.Table1", "Column1", true, "Column1_IX") 和 Down() DropIndex(("dbo.Table1 ", "Column1_IX")。我只是希望他们也添加了一个流利的 API...
    【解决方案9】:

    你可以使用其中之一

    // 索引

     this.HasIndex(e => e.IsActive)
                .HasName("IX_IsActive");
    

      this.Property(e => e.IsActive).HasColumnAnnotation(
                "Index",
                new IndexAnnotation(new IndexAttribute("IX_IsActive")));
    

    【讨论】:

      【解决方案10】:

      我写了一个扩展方法用在fluent EF中,避免额外的代码:

      public static PrimitivePropertyConfiguration HasIndexAnnotation(
          this PrimitivePropertyConfiguration primitivePropertyConfiguration, 
          IndexAttribute indexAttribute = null
          )
      {
          indexAttribute = indexAttribute ?? new IndexAttribute();
      
          return primitivePropertyConfiguration
              .HasColumnAnnotation(
                  IndexAnnotation.AnnotationName, 
                  new IndexAnnotation(indexAttribute)
              );
      }
      

      然后像这样使用它:

      Property(t => t.CardNo)
          .HasIndexAnnotation();
      

      如果索引需要一些配置,或者像这样:

      Property(t => t.CardNo)
          .HasIndexAnnotation(new IndexAttribute("IX_Account") { IsUnique = true });
      

      【讨论】:

        猜你喜欢
        • 2016-12-21
        • 2014-02-07
        • 2014-03-28
        • 1970-01-01
        • 2017-04-21
        • 1970-01-01
        • 2023-03-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多