Akıcı API ile benzersiz bir sınırlama belirlensin mi?


185

Önce kod ile bir EF varlık ve EntityTypeConfigurationakıcı bir API kullanarak çalışıyorum. Birincil Kısıtlama ile birincil anahtarlar oluşturmak kolaydır, ancak öyle değildir. Bunun için yerel SQL komutlarının yürütülmesini öneren eski mesajları görüyordum, ancak bu amacı yenmek gibi görünüyor. EF6 ile mümkün mü?

Yanıtlar:


275

On EF6.2 , kullanabileceğiniz HasIndex()akıcı API üzerinden geçiş için endeksler ekleyin.

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

Misal

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

Açık EF6.1 itibaren kullanabileceğiniz IndexAnnotation()sizin akıcı API göç dizinleri ekleyin.

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

Aşağıdakilere referans eklemelisiniz:

using System.Data.Entity.Infrastructure.Annotations;

Temel Örnek

İşte basit bir kullanım, User.FirstNamemülkiyet üzerinde bir dizin ekleme

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

Pratik Örnek:

İşte daha gerçekçi bir örnek. Birden çok özelliğe benzersiz bir dizin ekler : User.FirstNameve User.LastName"IX_FirstNameLastName" dizin adıyla

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
Bu, sütun ek açıklamasını "Dizin" olarak adlandırmak için gereklidir! Başka bir isim yazdım ve işe yaramadı! Gönderinizi orijinal "Index" olarak yeniden adlandırmayı denemeden önce saatler geçirdim ve bunun önemli olduğunu anladım. :( Dizede kodlama yapmamak için bir sabit olmalıdır.
Alexander Vasilyev

10
@AlexanderVasilyev Sabit olarak tanımlanırIndexAnnotation.AnnotationName
Nathan

3
@Nathan Teşekkür ederim! Bu kadar! Bu gönderideki örnek, bu sabit kullanılarak düzeltilmelidir.
Alexander Vasilyev


2
İlk örnekte IndexAttribute oluştururken IsUnique'ın true olarak ayarlanması gerektiğine inanıyorum. Bunun gibi: new IndexAttribute() { IsUnique = true }. Aksi takdirde, normal (benzersiz olmayan) bir dizin oluşturur.
jakubka

134

Yorro'nun cevabına ek olarak, bu özellikler kullanılarak da yapılabilir.

intTip benzersiz tuş kombinasyonu için örnek :

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

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

Veri türü ise string, o zaman MaxLengthnitelik eklenmelidir:

[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; }

Bir etki alanı / depolama modeli ayırma sorunu varsa, Metadatatypeniteliği / sınıfı kullanmak bir seçenek olabilir: https://msdn.microsoft.com/en-us/library/ff664465%28v=pandp.50%29.aspx?f= 255 ve MSPPError = -2147217396


Hızlı bir konsol uygulaması örneği:

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
Alan adı modelinizi depolama alanlarından tamamen ayrı tutmak istiyorsanız değil.
Rickard Liljeberg

4
Ayrıca EntityFramework
Michael Tranchida

2
Dizin özelliği Entity Framework'ten ayrıldıysa iyi olur, böylece Modeller projeme ekleyebilirim. Bunun bir depolama endişesi olduğunu anlıyorum, ancak kullanmamın ana nedeni UserNames ve Rol Names gibi şeylere benzersiz kısıtlamalar koymak.
Sam


4
SQL yalnızca nvarchar (max) 'ın anahtar olarak kullanılmasına izin vermediğinden, bu yalnızca dizenin uzunluğunu kısıtlarsanız çalışır .
JMK

17

Benzersiz dizinleri daha akıcı bir şekilde ayarlamak için bir uzantı yöntemi:

public static class MappingExtensions
{
    public static PrimitivePropertyConfiguration IsUnique(this PrimitivePropertyConfiguration configuration)
    {
        return configuration.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsUnique = true }));
    }
}

Kullanımı:

modelBuilder 
    .Entity<Person>() 
    .Property(t => t.Name)
    .IsUnique();

Aşağıdakiler gibi taşıma oluşturur:

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 akıcı API ile Benzersiz Dizin Oluşturma


16

@ coni2k 'nin cevabı doğrudur ancak [StringLength]çalışması için öznitelik eklemeniz gerekir, aksi takdirde geçersiz bir anahtar istisnası alırsınız (Örnek feryat).

[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; }


0
modelBuilder.Property(x => x.FirstName).IsUnicode().IsRequired().HasMaxLength(50);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.