如何使用 Entity Framework 核心创建聚簇索引

How to create a Clustered Index with Entity Framework Core

从 EF6.1 开始,我们有一种在 属性

上指定聚簇索引的方法
public class Person 
{
  [Index(IsClustered = true, IsUnique = true)]
  public long UserName { get; set; }
}

但是这个 Index 属性现在似乎不在 EF Core 中?在 EF Core 中,您如何实现这一点?

来自当前的 EF Core 文档 - Indexes 部分:

Data Annotations

Indexes can not be created using data annotations.

但是您可以肯定地通过 Fluent API 指定它(请注意具有 ForSqlServer 前缀的扩展方法似乎表示 SqlServer 特定功能):

modelBuilder.Entity<Person>()
    .HasIndex(e => e.UserName)
    .IsUnique()
    .ForSqlServerIsClustered();

更新: 对于 EF Core 3.0+,该方法仅被调用 IsClustered

modelBuilder.Entity<Person>()
    .HasIndex(e => e.UserName)
    .IsUnique()
    .IsClustered();

更新: 从 EF Core 5.0 开始,Indexes 文档 link 中现在提到了 Index 数据注释,但不能用于指定数据库特定属性,如集群(特定于 SqlServer),因此原始答案仍然适用。

在没有内置支持的情况下,您可以使用自己的自定义属性来注释模型属性并在OnModelCreating()中应用:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    foreach (var entity in modelBuilder.Model.GetEntityTypes())
    {
        foreach (var prop in entity.GetProperties())
        {
            var attr = prop.PropertyInfo.GetCustomAttribute<IndexAttribute>();
            if (attr != null)
            {
                var index = entity.AddIndex(prop);
                index.IsUnique = attr.IsUnique;
                index.SqlServer().IsClustered = attr.IsClustered;
            }
        }
    }
}

使用简单的标记属性class:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class IndexAttribute : Attribute
{
    public bool IsUnique { get; set; } 
    public bool IsClustered { get; set; } 
}

然后在你的模型中class,只需添加创建二级索引的属性:

public class User
{
    public int UserId { get; set; }
    [Index(IsUnique = true, IsClustered = true)]
    public string Nickname { get; set; }
}

或者这也行,比如你想按年龄聚类...

            modelBuilder
            .Entity<Person>()
            .Property(t => t.Age)
            .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute() { IsClustered = true}));

对于 EF Core 3.0+ 您现在可以使用 IsClustered:

modelBuilder.Entity<Person>()
.HasIndex(e => e.UserName)
.IsUnique()
.IsClustered();

.ForSqlServerIsClustered() 现已标记为过时。

另请注意,如果您在 table 上有一个主键,您可能还需要在为您的用户名添加集群之前明确删除其上的集群:

modelBuilder.Entity<Person>()
.HasKey(e => e.PersonId)
.IsClustered(false);

modelBuilder.Entity<Person>()
.HasIndex(e => e.UserName)
.IsUnique()
.IsClustered();