Первый уникальный столбец кода Entity Framework

114

Я использую Entity Framework 4.3 и использую Code Fist.

У меня есть класс

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

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

cpoDesign
источник

Ответы:

259

В Entity Framework 6.1+ вы можете использовать этот атрибут в своей модели:

[Index(IsUnique=true)]

Вы можете найти его в этом пространстве имен:

using System.ComponentModel.DataAnnotations.Schema;

Если поле вашей модели является строкой, убедитесь, что для него не установлено значение nvarchar (MAX) в SQL Server, иначе вы увидите эту ошибку с Entity Framework Code First:

Столбец «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 } }));
    }
  }

и используйте в своем modelBuilder:

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

Обновление 2

для EntityFrameworkCore см. также эту тему: https://github.com/aspnet/EntityFrameworkCore/issues/1698

Обновление 3

для EF6.2 см. https://github.com/aspnet/EntityFramework6/issues/274

Обновление 4

ASP.NET Core Mvc 2.2 с EF Core:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Unique { get; set; }
ЮФО
источник
23
Спасибо за ответ на старый пост этого парня с актуальной информацией!
Джим Ярбро
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
Это именно то, что я искал! Мне было интересно, можно ли добавить такие ограничения с помощью миграций.
Alex Jorgenson
@ Ладислав Мрнка: Возможно ли это также с помощью метода Seed?
Raheel Khan 01
2
Хотите привести пример? Спасибо!
Zero3
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 для аннотирования свойств индекса, что автоматически приведет к (уникальному) индексу в ваших Code First Migrations.

Robba
источник
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");
cpoDesign
источник
25
Будьте осторожны с этим раствором. Добавление Keyатрибута к UserNameсвойству приведет к тому, что UserNameсвойство станет первичным ключом в базе данных. Только UserIdсвойство должно быть помечено Keyатрибутом. Это решение даст вам «правильное» поведение на стороне программирования и даст вам неправильный дизайн базы данных.
Alex Jorgenson