web-dev-qa-db-ja.com

Entity Framework 6.1 Fluent APIを使用した一意のインデックスの作成

「名前」という列があり、それは一意である必要があります。外部キーなどはありません。

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

Anatoliiの答えに基づいて、一意のインデックスをより流settingに設定するための拡張方法を次に示します。

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" });
    }
}
36
Geir Sagberg

既に素晴らしい回答が存在するため、この回答には追加情報のみが含まれています。

インデックスに複数の一意のフィールドが必要な場合は、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のインデックスも必要だとしましょう。

wrongそれを行う方法は、newthis.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
                }
            }
        )
    );
_

最後に、インデックス/ユニークのソート順も変更したい場合、以下を見ることができます:

Fluent APIを使用してASC/DESCソートで複数の列にインデックスを追加する方法

28
Maxime

EFの新しいバージョン6.2では、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

8
Soheil Alizadeh

移行ファイルに一意のインデックスを作成できます。

パッケージマネージャーで:

  1. 移行の有効化
  2. Add-Migration InitialMigration

これにより、Migrationsフォルダーにタイムスタンプ付きの新しいファイルが作成されます。このクラスには、インデックスの作成に使用できるUpおよびDownメソッドがあります。

public override void Up()
{
    // ... 
    CreateIndex("tableName", "columnName", unique: true, name: "myIndex");
}

public override void Down()
{
    // ...
    DropIndex("tableName", "myIndex");
}

移行を実行するには、パッケージマネージャーでUpdate-Databaseと入力します。

また、テーブルを作成する移行の一部としてインデックスを追加することもできます。

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);
4
Dismissile

私にとって、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); 
}
0
Oscar