Налаштування унікального обмеження на плавному API?


185

Я намагаюся створити об'єкт EF з кодом спочатку та EntityTypeConfigurationвикористовуючи вільний API. створити первинні ключі легко, але це не так з унікальним обмеженням. Я бачив старі публікації, які пропонували виконувати для цього нативні команди SQL, але це, здається, перемагає мету. це можливо за допомогою EF6?

Відповіді:


275

На EF6.2 ви можете використовувати HasIndex()для додавання індексів для міграції через вільний API.

https://github.com/aspnet/EntityFramework6/isissue/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.FirstNameі User.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
@Nathan Дякую! Це воно! Приклад у цій публікації повинен бути виправлений за допомогою цієї константи.
Олександр Васильєв

2
Не можу знайти його в EF7 - DNX
Shimmy Weitzhandler

2
Я вважаю, що IsUnique потрібно встановити на істину під час створення IndexAttribute у першому прикладі. Як це: new IndexAttribute() { IsUnique = true }. Інакше він створює просто звичайний (не унікальний) індекс.
jakubka

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
Якщо ви не хочете, щоб ваша модель домену була повністю відокремлена від проблем із зберіганням.
Рікард Лілберг

4
Вам також потрібно переконатися, що у вас є посилання на EntityFramework
Michael Tranchida

2
Буде добре, якщо атрибут Index був відокремлений від Entity Framework, щоб я міг включити його до свого проекту «Моделі». Я розумію, що це проблема зберігання, але головна причина, яку я використовую, полягає в тому, щоб ставити унікальні обмеження на такі речі, як UserNames та Role Names.
Сем

2
Не можу знайти його в EF7 - DNX
Shimmy Weitzhandler

4
Це працює лише в тому випадку, якщо ви також обмежуєте довжину рядка, оскільки SQL не дозволяє nvarchar (max) використовувати як ключ.
JMK

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: Створення унікального індексу з вільним API API Entity Framework 6.1


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


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.