Код Entity Framework перший унікальний стовпець


114

Я використовую Entity Framework 4.3 і використовую Code Fist.

У мене клас

public class User
{
   public int UserId{get;set;}
   public string UserName{get;set;}
}

Як сказати Entity Framework, що UserName повинен бути унікальним при створенні таблиці баз даних? Я вважаю за краще використовувати анотації даних, а не файл конфігурації, якщо це можливо.

Відповіді:


257

В Entity Framework 6.1+ ви можете використовувати цей атрибут на своїй моделі:

[Index(IsUnique=true)]

Ви можете знайти його в цьому просторі імен:

using System.ComponentModel.DataAnnotations.Schema;

Якщо ваше поле моделі є рядком, переконайтеся, що воно не встановлено на nvarchar (MAX) на SQL Server, або ви побачите цю помилку з Entity Framework Code спочатку:

Стовпець 'x' у таблиці 'dbo.y' має тип, який недійсний для використання в якості ключового стовпця в індексі.

Причина через це:

SQL Server зберігає обмеження в 900 байт для максимального загального розміру всіх стовпців ключових індексів. "

(від: http://msdn.microsoft.com/en-us/library/ms191241.aspx )

Ви можете вирішити це, встановивши максимальну довжину рядка для вашої моделі:

[StringLength(450)]

Ваша модель буде виглядати приблизно так у EF CF 6.1+:

public class User
{
   public int UserId{get;set;}
   [StringLength(450)]
   [Index(IsUnique=true)]
   public string UserName{get;set;}
}

Оновлення:

якщо ви використовуєте Fluent:

  public class UserMap : EntityTypeConfiguration<User>
  {
    public UserMap()
    {
      // ....
      Property(x => x.Name).IsRequired().HasMaxLength(450).HasColumnAnnotation("Index", new IndexAnnotation(new[] { new IndexAttribute("Index") { IsUnique = true } }));
    }
  }

і використовуйте у своїй моделіBuilder:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  // ...
  modelBuilder.Configurations.Add(new UserMap());
  // ...
}

Оновлення 2

для EntityFrameworkCore див. також цю тему: https://github.com/aspnet/EntityFrameworkCore/isissue/1698

Оновлення 3

для EF6.2 див .: https://github.com/aspnet/EntityFramework6/isissue/274

Оновлення 4

ASP.NET Core Mvc 2.2 з EF Core:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Unique { get; set; }

23
Дякуємо, що відповіли на старе повідомлення цього хлопця з актуальною поточною інформацією!
Jim Yarbro

3
чому індекс, чому не просто обмеження?
Джон Генкель

2
Щоб відповісти на питання індексу проти "There are no significant differences between creating a UNIQUE constraint and creating a unique index that is independent of a constraint. Data validation occurs in the same manner, and the query optimizer does not differentiate between a unique index created by a constraint or manually created. However, creating a UNIQUE constraint on the column makes the objective of the index clear." контракту
user919426

3
Примітка; в Entity Framework Core 1.0.0-preview2-final метод анотацій даних недоступний - docs.efproject.net/en/latest/modeling/…
Едвард Комо

26

EF не підтримує унікальні стовпці, крім клавіш. Якщо ви використовуєте EF Migrations, ви можете змусити EF створити унікальний індекс на UserNameстовпчику (в коді міграції, а не за допомогою анотації), але унікальність буде застосована лише в базі даних. Якщо ви спробуєте зберегти повторюване значення, вам доведеться зловити виняток (порушення обмеження), запущений базою даних.


1
Це саме те, що я шукав! Мені було цікаво, чи можна додати такі обмеження за допомогою міграцій.
Алекс Йоргенсон

@Ladislav Mrnka: Чи можливо це також методом насіння?
Рахіль Хан

2
Хочете навести приклад? Дякую!
Нуль3

10

З вашого коду стає очевидним, що ви використовуєте POCO. Маючи ще один ключ, зайве: ви можете додати індекс, як пропонує juFo .
Якщо ви використовуєте Fluent API замість того, щоб призначати властивість UserName, анотація стовпця має виглядати так:

this.Property(p => p.UserName)
    .HasColumnAnnotation("Index", new IndexAnnotation(new[] { 
        new IndexAttribute("Index") { IsUnique = true } 
    }
));

Це створить такий сценарій SQL:

CREATE UNIQUE NONCLUSTERED INDEX [Index] ON [dbo].[Users]
(
    [UserName] ASC
)
WITH (
    PAD_INDEX = OFF, 
    STATISTICS_NORECOMPUTE = OFF, 
    SORT_IN_TEMPDB = OFF, 
    IGNORE_DUP_KEY = OFF, 
    DROP_EXISTING = OFF, 
    ONLINE = OFF, 
    ALLOW_ROW_LOCKS = ON, 
    ALLOW_PAGE_LOCKS = ON
) ON [PRIMARY]

Якщо ви спробуєте вставити кілька користувачів, що мають одне і те ж ім’я користувача, ви отримаєте DbUpdateException із таким повідомленням:

Cannot insert duplicate key row in object 'dbo.Users' with unique index 'Index'. 
The duplicate key value is (...).
The statement has been terminated.

Знову ж, анотації стовпців недоступні в Entity Framework до версії 6.1.


А як же створити індекс із змішаними стовпцями за допомогою конфігурації?
FindOutIslamNow

Один є на UserName, а інший?
Олександр Христов

5

Зауважте, що в Entity Framework 6.1 (зараз знаходиться в бета-версії) буде підтримуватися IndexAttribute для анотування властивостей індексу, що автоматично призведе до (унікального) індексу у вашій міграції коду.


2

У EF 6.2 за допомогою FluentAPI ви можете використовуватиHasIndex()

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

-13

Рішення для EF4.3

Унікальне ім’я користувача

Додайте примітку до даних над стовпцем як:

 [Index(IsUnique = true)]
 [MaxLength(255)] // for code-first implementations
 public string UserName{get;set;}

Унікальний ідентифікатор , я додав прикрасу [Ключ] до мого стовпця і закінчив. Це ж рішення, як описано тут: https://msdn.microsoft.com/en-gb/data/jj591583.aspx

IE:

[Key]
public int UserId{get;set;}

Альтернативні відповіді

з використанням анотації даних

[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("UserId")]

за допомогою картографування

  mb.Entity<User>()
            .HasKey(i => i.UserId);
        mb.User<User>()
          .Property(i => i.UserId)
          .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
          .HasColumnName("UserId");

25
Будьте обережні з цим рішенням. Додавання Keyатрибута до UserNameвластивості призведе до того, що UserNameвластивість стане первинним ключем у базі даних. Тільки UserIdвластивість має бути позначена Keyатрибутом. Це рішення дасть вам "правильну" поведінку на стороні програмування, одночасно надаючи неправильний дизайн бази даних.
Алекс Йоргенсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.