web-dev-qa-db-de.com

Festlegen einer eindeutigen Einschränkung mit flüssiger API?

Ich versuche, eine EF-Entität mit Code First und einem EntityTypeConfiguration mithilfe einer fließenden API zu erstellen. Das Erstellen von Primärschlüsseln ist mit einer eindeutigen Einschränkung einfach, aber nicht so. Ich habe alte Posts gesehen, in denen vorgeschlagen wurde, native SQL-Befehle dafür auszuführen, die jedoch den Zweck zu umgehen scheinen. ist das mit EF6 möglich?

176
kob490

Unter EF6.2 können Sie mit HasIndex() Indizes für die Migration über eine flüssige API hinzufügen.

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

Beispiel

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

Ab EF6.1 können Sie mit IndexAnnotation() Indizes für die Migration in Ihrer flüssigen API hinzufügen.

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

Sie müssen einen Verweis hinzufügen auf:

using System.Data.Entity.Infrastructure.Annotations;

Grundlegendes Beispiel

Hier ist eine einfache Anwendung, die einen Index für die Eigenschaft User.FirstName Hinzufügt

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

Praktisches Beispiel:

Hier ist ein realistischeres Beispiel. Es wird ein eindeutiger Index für mehrere Eigenschaften hinzugefügt: User.FirstName Und User.LastName Mit einem Indexnamen "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 }));
261
Yorro

Als Ergänzung zu Yorros Antwort können auch Attribute verwendet werden.

Beispiel für eine eindeutige Tastenkombination vom Typ 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; }

Wenn der Datentyp string ist, muss das Attribut MaxLength hinzugefügt werden:

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

Bei Problemen mit der Trennung von Domäne und Speichermodell kann die Verwendung des Attributs/der Klasse Metadatatype eine Option sein: https://msdn.Microsoft.com/en-us/library/ff664465%28v=) pandp.50% 29.aspx? f = 255 & MSPPError = -2147217396


Ein kurzes Beispiel für eine Konsolen-App:

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; }
    }
}
133
coni2k

Hier ist eine Erweiterungsmethode, um eindeutige Indizes flüssiger festzulegen:

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

Verwendungszweck:

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

Erzeugt Migration wie:

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: Erstellen eines eindeutigen Index mit der fließenden API von Entity Framework 6.1

17

Die Antwort von @ coni2k ist korrekt, Sie müssen jedoch das Attribut [StringLength] hinzufügen, damit es funktioniert. Andernfalls wird eine ungültige Schlüsselausnahme ausgegeben (Beispiel unten).

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

Leider wird dies in Entity Framework nicht unterstützt. Es war auf der Roadmap für EF 6, wurde aber zurückgedrängt: Workitem 299: Unique Constraints (Unique Indexes)

10
Kenneth

Inzwischen gibt es folgendes:

niqueAttribute, das ein eindeutiges Feld anhand der anderen Zeilen in der Datenbank überprüft, übernimmt DataAnnotations.ValidationAttribute .

Entschuldigung, dass Sie den Code nicht kopieren, er ist etwas lang.

0
Shimmy