Fluent APIで一意の制約を設定しますか?


185

私は、コードファーストでEFエンティティを構築し、EntityTypeConfiguration流暢なAPIを使用しようとしています。主キーの作成は簡単ですが、一意制約を使用すると簡単ではありません。このためにネイティブSQLコマンドの実行を提案する古い投稿を見ていましたが、それでは目的が達成されないようです。これはEF6で可能ですか?

回答:


275

EF6.2は、使用することができますHasIndex()流暢なAPIを介して移行のためにインデックスを追加します。

https://github.com/aspnet/EntityFramework6/issues/274

modelBuilder
    .Entity<User>()
    .HasIndex(u => u.Email)
        .IsUnique();

EF6.1以降は、使用することができますIndexAnnotation()あなたの流暢なAPIに移行するためにインデックスを追加します。

http://msdn.microsoft.com/en-us/data/jj591617.aspx#PropertyIndex

以下への参照を追加する必要があります。

using System.Data.Entity.Infrastructure.Annotations;

基本的な例

これは、User.FirstNameプロパティにインデックスを追加する簡単な使用法です

modelBuilder 
    .Entity<User>() 
    .Property(t => t.FirstName) 
    .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));

実用的な例:

これはより現実的な例です。それは追加ユニークインデックスを複数のプロパティに:User.FirstNameUser.LastName、インデックス名「IX_FirstNameLastName」と

modelBuilder 
    .Entity<User>() 
    .Property(t => t.FirstName) 
    .IsRequired()
    .HasMaxLength(60)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(
            new IndexAttribute("IX_FirstNameLastName", 1) { IsUnique = true }));

modelBuilder 
    .Entity<User>() 
    .Property(t => t.LastName) 
    .IsRequired()
    .HasMaxLength(60)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(
            new IndexAttribute("IX_FirstNameLastName", 2) { IsUnique = true }));

4
これは、列の注釈に「インデックス」という名前を付けるために必要です!別の名前を書いてもうまくいきませんでした!あなたの投稿のように、元の「インデックス」に名前を変更する前に何時間も費やし、これが重要であることを理解しました。:(ないハードコードする枠組みの中で、それのための文字列定数が存在する必要があります。
アレクサンダー・バジライバ

10
@AlexanderVasilyev定数は以下のように定義されるIndexAnnotation.AnnotationName
ネイサン

3
@ネイサンありがとうございます!それでおしまい!この投稿の例は、この定数を使用して修正する必要があります。
Alexander Vasilyev 2014

2
EF7でそれを見つけることができないようです-DNX
Shimmy Weitzhandler 2015

2
最初の例でIndexAttributeを作成するときは、IsUniqueをtrueに設定する必要があると思います。このように:new IndexAttribute() { IsUnique = true }。それ以外の場合は、通常の(一意でない)インデックスのみを作成します。
jakubka 2016

134

ヨロの答えに加えて、属性を使用して行うこともできます。

intタイプの一意のキーの組み合わせのサンプル:

[Index("IX_UniqueKeyInt", IsUnique = true, Order = 1)]
public int UniqueKeyIntPart1 { get; set; }

[Index("IX_UniqueKeyInt", IsUnique = true, Order = 2)]
public int UniqueKeyIntPart2 { get; set; }

データ型の場合string、そのMaxLength属性が追加する必要があります。

[Index("IX_UniqueKeyString", IsUnique = true, Order = 1)]
[MaxLength(50)]
public string UniqueKeyStringPart1 { get; set; }

[Index("IX_UniqueKeyString", IsUnique = true, Order = 2)]
[MaxLength(50)]
public string UniqueKeyStringPart2 { get; set; }

ドメイン/ストレージモデルの分離に関する懸念がある場合は、Metadatatype属性/クラスの使用がオプションになる可能性があります。https//msdn.microsoft.com/en-us/library/ff664465%28v=pandp.50%29.aspx?f = 255&MSPPError = -2147217396


簡単なコンソールアプリの例:

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

namespace EFIndexTest
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new AppDbContext())
            {
                var newUser = new User { UniqueKeyIntPart1 = 1, UniqueKeyIntPart2 = 1, UniqueKeyStringPart1 = "A", UniqueKeyStringPart2 = "A" };
                context.UserSet.Add(newUser);
                context.SaveChanges();
            }
        }
    }

    [MetadataType(typeof(UserMetadata))]
    public class User
    {
        public int Id { get; set; }
        public int UniqueKeyIntPart1 { get; set; }
        public int UniqueKeyIntPart2 { get; set; }
        public string UniqueKeyStringPart1 { get; set; }
        public string UniqueKeyStringPart2 { get; set; }
    }

    public class UserMetadata
    {
        [Index("IX_UniqueKeyInt", IsUnique = true, Order = 1)]
        public int UniqueKeyIntPart1 { get; set; }

        [Index("IX_UniqueKeyInt", IsUnique = true, Order = 2)]
        public int UniqueKeyIntPart2 { get; set; }

        [Index("IX_UniqueKeyString", IsUnique = true, Order = 1)]
        [MaxLength(50)]
        public string UniqueKeyStringPart1 { get; set; }

        [Index("IX_UniqueKeyString", IsUnique = true, Order = 2)]
        [MaxLength(50)]
        public string UniqueKeyStringPart2 { get; set; }
    }

    public class AppDbContext : DbContext
    {
        public virtual DbSet<User> UserSet { get; set; }
    }
}

45
ドメインモデルをストレージの問題とは完全に分離したい場合はそうではありません。
Rickard Liljeberg、2014年

4
EntityFrameworkへの参照があることを確認する必要もあります
Michael Tranchida

2
Index属性がEntity Frameworkから分離されている場合は、モデルプロジェクトに含めることができるようにしてください。ストレージの問題であることは理解していますが、主な理由は、ユーザー名やロール名などに固有の制約を課すことです。
サム

2
EF7でそれを見つけることができないようです-DNX
Shimmy Weitzhandler 2015

4
SQLではnvarchar(max)をキーとして使用できないため、これは文字列の長さも制限する場合にのみ機能します。
JMK 2016

17

一意のインデックスをより滑らかに設定するための拡張メソッドを次に示します。

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

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


16

@ coni2kの答えは正しいですが、動作さ[StringLength]せるには属性を追加する必要があります。そうしないと、無効なキーの例外が発生します(以下の例)。

[StringLength(65)]
[Index("IX_FirstNameLastName", 1, IsUnique = true)]
public string FirstName { get; set; }

[StringLength(65)]
[Index("IX_FirstNameLastName", 2, IsUnique = true)]
public string LastName { get; set; }


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.