Ustawiasz wyjątkowe ograniczenie dzięki płynnemu API?

185

Próbuję zbudować jednostkę EF z kodem Najpierw i za EntityTypeConfigurationpomocą płynnego interfejsu API. tworzenie kluczy podstawowych jest łatwe, ale nie jest tak dzięki Unikalnemu Ograniczeniu. Widziałem stare posty sugerujące wykonywanie natywnych poleceń SQL w tym celu, ale wydaje się, że to nie udaje się. czy jest to możliwe dzięki EF6?

kob490
źródło

Odpowiedzi:

275

W wersji EF6.2 można używać HasIndex()do dodawania indeksów do migracji za pomocą płynnego interfejsu API.

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

Przykład

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

Na EF6.1 roku, można użyć IndexAnnotation(), aby dodać indeksy do migracji w biegle API.

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

Musisz dodać odniesienie do:

using System.Data.Entity.Infrastructure.Annotations;

Podstawowy przykład

Oto proste użycie, dodanie indeksu do User.FirstNamewłaściwości

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

Praktyczny przykład:

Oto bardziej realistyczny przykład. Dodaje unikalny indeks do wielu właściwości: User.FirstNameoraz User.LastNameo nazwie indeksu „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 }));
Yorro
źródło
4
Jest to wymagane do nazwania adnotacji w kolumnie „Indeks”! Napisałem inne imię i to nie działało! Spędziłem godziny, zanim spróbowałem zmienić nazwę na oryginalny „Indeks” jak w twoim poście i zrozumiałem, że to ważne. :( Musi istnieć stała w ramach, aby nie kodować łańcucha na stałe.
Alexander Vasilyev
10
@AlexanderVasilyev Stała jest zdefiniowana jakoIndexAnnotation.AnnotationName
Nathan
3
@Nathan Dziękujemy! Otóż ​​to! Przykład w tym poście musi zostać poprawiony przy użyciu tej stałej.
Aleksander Wasiljew
2
Nie można go znaleźć w EF7 - DNX
Shimmy Weitzhandler
2
Uważam, że IsUnique należy ustawić na true podczas tworzenia IndexAttribute w pierwszym przykładzie. Tak: new IndexAttribute() { IsUnique = true }. W przeciwnym razie tworzy tylko zwykły (nieunikalny) indeks.
jakubka
134

Jako dodatek do odpowiedzi Yorro, można to również zrobić za pomocą atrybutów.

Przykład dla intunikalnej kombinacji klawiszy typu:

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

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

Jeśli typ danych to string, MaxLengthnależy dodać atrybut:

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

Jeśli istnieje problem z rozdzieleniem domeny / modelu pamięci, użycie Metadatatypeatrybutu / klasy może być opcją: https://msdn.microsoft.com/en-us/library/ff664465%28v=pandp.50%29.aspx?f= 255 i MSPPError = -2147217396


Przykład szybkiej aplikacji na konsolę:

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; }
    }
}
coni2k
źródło
45
Nie, jeśli chcesz całkowicie oddzielić swój model domeny od problemów związanych z pamięcią masową.
Rickard Liljeberg
4
Musisz także upewnić się, że masz odniesienie do EntityFramework
Michael Tranchida
2
Bądź miły, jeśli atrybut Index został oddzielony od Entity Framework, abym mógł uwzględnić go w moim projekcie Modele. Rozumiem, że jest to problem z pamięcią masową, ale głównym powodem, dla którego go używam, jest nałożenie unikalnych ograniczeń na takie rzeczy, jak UserNames i Role Names.
Sam
2
Nie można go znaleźć w EF7 - DNX
Shimmy Weitzhandler
4
Działa to tylko wtedy, gdy ograniczysz również długość łańcucha, ponieważ SQL nie pozwala na użycie nvarchar (max) jako klucza.
JMK
17

Oto metoda rozszerzenia pozwalająca na płynniejsze ustawianie unikalnych indeksów:

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

Stosowanie:

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

Wygeneruje migrację, taką jak:

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: Tworzenie unikalnego indeksu za pomocą płynnego interfejsu API Entity Framework 6.1

Bartho Bernsmann
źródło
16

Odpowiedź @ coni2k jest poprawna, jednak musisz dodać [StringLength]atrybut, aby działał, w przeciwnym razie otrzymasz niepoprawny kluczowy wyjątek (przykład poniżej).

[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; }
Arijoon
źródło
0
modelBuilder.Property(x => x.FirstName).IsUnicode().IsRequired().HasMaxLength(50);
Rousonur Jaman
źródło