Entity Framework Core добавляет уникальный код ограничения в первую очередь

152

Я не могу найти способ добавить уникальное ограничение к моему полю с помощью атрибута:

public class User
{
    [Required]
    public int Id { get; set; }

    [Required]
    // [Index("IX_FirstAndSecond", 2, IsUnique = true)] not supported by core
    public string Email { get; set; }

    [Required]
    public string Password { get; set; }
}

Я использую эти пакеты:

 "Microsoft.EntityFrameworkCore": "1.0.1",
 "Microsoft.EntityFrameworkCore.SqlServer": "1.0.1",
 "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.1",
 "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
Вадим М
источник
Образцы беглого API для индексов см. По адресу learnentityframeworkcore.com/configuration/fluent-api/…
Майкл Фрейдгейм,

Ответы:

301

В ядре EF вы не можете создавать индексы с помощью аннотаций данных. Но вы можете сделать это с помощью Fluent API.

Вот так внутри {Db}Context.cs:

protected override void OnModelCreating(ModelBuilder builder)
{
    builder.Entity<User>()
        .HasIndex(u => u.Email)
        .IsUnique();
}

... или если вы используете перегрузку с buildAction:

protected override void OnModelCreating(ModelBuilder builder)
{
    builder.Entity<User>(entity => {
        entity.HasIndex(e => e.Email).IsUnique();
    });
}

Вы можете прочитать больше об этом здесь: Индексы

Сампатх
источник
1
Большое спасибо за вашу помощь, это правильное решение!
Вадим М
В случае, если кто-то приземлится здесь в поисках решения, которое работает при использовании схемы MS Identity, я предлагаю установить уникальное ограничение в поле NormalizedEmail, а не в Email (объекта AspNetUsers). Использование другого регистра может не привести к нарушению ограничения, даже если это один и тот же адрес электронной почты, в зависимости от параметров сортировки БД.
Том
4
Этот код не работает для столбца типа строка :( Есть ли способ добавить уникальное ограничение для столбца строки?
Джохар Заман
Перейти наHasAlternateKey
Чамика Сандамал
1
Я попробовал это, когда работал над этим, но теперь мне не нужно это реализовывать. Кстати, спасибо за ваш комментарий. @Sampath
Джохар Заман
70

Также, если вы хотите создать уникальные ограничения для нескольких столбцов, вы можете просто сделать это (по ссылке @ Sampath )

class MyContext : DbContext
{
    public DbSet<Person> People { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
            .HasIndex(p => new { p.FirstName, p.LastName })
            .IsUnique(true);
    }
}

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
Хоссейн Наримани Рад
источник
9

Решение для EF Core

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Passport { get; set; }
}

public class ApplicationContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public ApplicationContext()
    {
        Database.EnsureCreated();
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=efbasicsappdb;Trusted_Connection=True;");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>().HasAlternateKey(u => u.Passport);
        //or: modelBuilder.Entity<User>().HasAlternateKey(u => new { u.Passport, u.Name})
    }
}

Таблица БД будет выглядеть так:

CREATE TABLE [dbo].[Users] (
    [Id]       INT            IDENTITY (1, 1) NOT NULL,
    [Name]     NVARCHAR (MAX) NULL,
    [Passport] NVARCHAR (450) NOT NULL,
    CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [AK_Users_Passport] UNIQUE NONCLUSTERED ([Passport] ASC)
);

Ссылка на документацию EF Core

Евгений Мирошниченко
источник
11
В соответствии с документами EF Core:If you just want to enforce uniqueness of a column then you want a unique index rather than an alternate key. In EF, alternate keys provide greater functionality than unique indexes because they can be used as the target of a foreign key.
bigworld12
Ссылка на комментарий bigworld12
granadaCoder
3

ОП спрашивает, возможно ли добавить атрибут в класс сущности для уникального ключа. Короткий ответ: это возможно, но не из коробки от EF Core Team. Если вы хотите использовать атрибут для добавления уникальных ключей в ваши классы сущностей Entity Framework Core, вы можете сделать то, что я разместил здесь

public class Company
{
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid CompanyId { get; set; }

    [Required]
    [UniqueKey(groupId: "1", order: 0)]
    [StringLength(100, MinimumLength = 1)]
    public string CompanyName { get; set; }

    [Required]
    [UniqueKey(groupId: "1", order: 1)]
    [StringLength(100, MinimumLength = 1)]
    public string CompanyLocation { get; set; }
}
Джастин Таббс
источник
Атрибут [UniqueKey] является определенным атрибутом Microsoft? или это надо определить самому?
Мохаммед Осман
Атрибут [UniqueKey] - это пользовательский атрибут, который я разработал, чтобы включить добавление уникальных ключей в классы сущностей .cs (а не через метод OnModelCreating () DbContext)
Джастин Таббс,
3
Замечательно. Не могли бы вы поместить код пользовательского атрибута, который вы разработали ?!
Мухаммед Осман
stackoverflow.com/questions/49526370/…
Джастин Таббс
2

Для кого-то, кто пробует все эти решения, но не работает, попробуйте этот, он работал для меня

protected override void OnModelCreating(ModelBuilder builder)
{

    builder.Entity<User>().Property(t => t.Email).HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_EmailIndex") { IsUnique = true }));

}
Shonie
источник
2

Чтобы использовать его в ядре EF через конфигурацию модели

public class ApplicationCompanyConfiguration : IEntityTypeConfiguration<Company>
{
    public void Configure(EntityTypeBuilder<Company> builder)
    {
        builder.ToTable("Company"); 
        builder.HasIndex(p => p.Name).IsUnique();
    }
}
valentasm
источник
1

Ни один из этих методов не работал для меня в .NET Core 2.2, но я смог адаптировать некоторый код для определения другого первичного ключа для работы с этой целью.

В приведенном ниже примере я хочу убедиться, что поле OutletRef уникально:

public class ApplicationDbContext : IdentityDbContext
    {
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Outlet>()
                .HasIndex(o => new { o.OutletRef });
        }
    }

Это добавляет необходимый уникальный индекс в базу данных. Чего он не делает, так это предоставит возможность указать пользовательское сообщение об ошибке.

Робин Уилсон
источник
0

Мы можем добавить уникальный индекс ключа, используя свободный API. Ниже код работал для меня

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        modelBuilder.Entity<User>().Property(p => p.Email).HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_EmailIndex") { IsUnique = true }));

    }
Кулдип Сингх
источник
0

Ef Core поддерживает несколько уникальных ключей

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  modelBuilder.Entity<Account>()
      .HasKey(item => new { item.Email, item.RoleId });
}

Не забудьте запустить команду ef core, чтобы выполнить миграцию и обновить базу данных.

>> dotnet ef migrations add MigrationName -c YourDbContextName
>> dotnet ef database update -c YourDbContextName
kdgilang
источник