Entity Framework Core dodaj najpierw kod ograniczenia unikalnego

152

Nie mogę znaleźć sposobu na dodanie unikalnego ograniczenia do mojego pola przy użyciu atrybutu:

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

Używam tych pakietów:

 "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",
Vadim M.
źródło
Przykłady płynnego interfejsu API
Michael Freidgeim

Odpowiedzi:

301

W EF core nie można tworzyć indeksów przy użyciu adnotacji danych, ale można to zrobić za pomocą interfejsu API Fluent.

Jak to w twoim {Db}Context.cs:

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

... lub jeśli używasz przeciążenia z buildAction:

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

Więcej na ten temat przeczytasz tutaj: Indeksy

Sampath
źródło
1
Bardzo dziękuję za pomoc, to dobre rozwiązanie!
Vadim M
W przypadku, gdy ktoś wyląduje tutaj i szuka rozwiązania, które działa przy korzystaniu ze schematu MS Identity, sugeruję ustawienie unikalnego ograniczenia w polu NormalizedEmail, a nie Email (jednostki AspNetUsers). Używanie różnych wielkości liter może nie naruszyć ograniczenia, nawet jeśli jest to ten sam adres e-mail, w zależności od ustawienia sortowania bazy danych.
Tom
4
Ten kod nie działa dla kolumny typu ciąg :( Czy istnieje sposób na dodanie unikalnego ograniczenia do kolumny ciągu?
Johar Zaman
Idź naHasAlternateKey
Chamika Sandamal
1
Próbowałem tego, kiedy nad tym pracowałem, ale teraz nie muszę tego wdrażać. Btw Dziękuję za komentarz. @Sampath
Johar Zaman
70

Również jeśli chcesz utworzyć unikalne ograniczenia w wielu kolumnach, możesz po prostu to zrobić (podążając za linkiem @ 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; }
}
Hossein Narimani Rad
źródło
9

Rozwiązanie dla 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})
    }
}

Tablica DB będzie wyglądać następująco:

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

Odwołaj się do dokumentów EF Core

Evgeniy Miroshnichenko
źródło
11
Według dokumentów 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
Odniesienie do komentarza bigworld12
granadaCoder
3

OP pyta, czy możliwe jest dodanie atrybutu do klasy jednostki dla unikalnego klucza. Krótka odpowiedź jest taka, że ​​JEST to możliwe, ale nie jest to standardowa funkcja zespołu EF Core. Jeśli chcesz użyć atrybutu, aby dodać unikalne klucze do klas encji Entity Framework Core, możesz zrobić to, co tutaj opublikowałem

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; }
}
Justin Tubbs
źródło
Atrybut [UniqueKey] jest atrybutem zdefiniowanym przez firmę Microsoft? czy należy samemu to zdefiniować?
Mohammed Osman
Atrybut [UniqueKey] jest niestandardowym atrybutem, który opracowałem, aby umożliwić dodawanie unikalnych kluczy w klasach encji .cs (a nie za pomocą metody OnModelCreating () DbContext)
Justin Tubbs
3
To wspaniale. Czy mógłbyś umieścić kod utworzonego przez siebie atrybutu niestandardowego ?!
Mohammed Osman
2

Dla kogoś, kto wypróbowuje wszystkie te rozwiązania, ale nie działa, wypróbuj to, zadziałało

protected override void OnModelCreating(ModelBuilder builder)
{

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

}
Shonie
źródło
2

Aby użyć go w rdzeniu EF za pośrednictwem konfiguracji modelu

public class ApplicationCompanyConfiguration : IEntityTypeConfiguration<Company>
{
    public void Configure(EntityTypeBuilder<Company> builder)
    {
        builder.ToTable("Company"); 
        builder.HasIndex(p => p.Name).IsUnique();
    }
}
walentynki
źródło
1

Żadna z tych metod nie działała dla mnie w .NET Core 2.2, ale byłem w stanie dostosować kod, który miałem do zdefiniowania innego klucza podstawowego, aby działał w tym celu.

W poniższym przypadku chcę się upewnić, że pole OutletRef jest unikalne:

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

Spowoduje to dodanie wymaganego unikalnego indeksu w bazie danych. Jednak to nie zapewnia możliwości określenia niestandardowego komunikatu o błędzie.

Robin Wilson
źródło
0

Możemy dodać unikalny indeks klucza za pomocą Fluent API. Poniższy kod zadziałał dla mnie

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

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

    }
Kuldeep Singh
źródło