Entity Framework Core aggiunge un codice di vincolo univoco per primo


152

Non riesco a trovare il modo di aggiungere un vincolo univoco al mio campo utilizzando l'attributo:

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

Sto usando questi pacchetti:

 "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",

Risposte:


301

Sul core EF non è possibile creare indici utilizzando le annotazioni dei dati, ma è possibile farlo utilizzando l'API Fluent.

In questo modo nel tuo {Db}Context.cs:

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

... o se stai usando il sovraccarico con buildAction:

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

Puoi leggere di più qui: Indici


1
Grazie mille per il tuo aiuto, è la soluzione giusta!
Vadim M,

Nel caso in cui qualcuno arrivi qui alla ricerca di una soluzione che funzioni quando si utilizza lo schema di MS Identity, suggerisco di impostare il vincolo univoco sul campo NormalizedEmail, non su Email (dell'entità AspNetUsers). L'uso di casi diversi potrebbe non riuscire a violare il vincolo anche se si tratta dello stesso indirizzo e-mail, a seconda delle impostazioni di confronto del database.
Tom,

4
Questo codice non funziona per la colonna di tipo stringa :( Esiste un modo per aggiungere un vincolo univoco alla colonna stringa?
Johar Zaman,

Go forHasAlternateKey
Chamika Sandamal

1
Ho provato questo mentre ci stavo lavorando ma ora non ho bisogno di implementarlo. Btw Grazie per il tuo commento. @Sampath
Johar Zaman,

70

Inoltre, se vuoi creare vincoli univoci su più colonne, puoi semplicemente farlo (seguendo il link di @ 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

Soluzione per 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})
    }
}

La tabella DB avrà questo aspetto:

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

Fare riferimento ai documenti EF Core


11
Secondo i documenti 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

Riferimento al commento di bigworld12
granadaCoder

3

L'OP chiede se è possibile aggiungere un attributo a una classe Entity per una chiave univoca. La risposta breve è che è possibile, ma non una funzionalità predefinita dell'EF Core Team. Se desideri utilizzare un attributo per aggiungere chiavi uniche alle classi di entità Core di Entity Framework, puoi fare ciò che ho pubblicato qui

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

L'attributo [UniqueKey] è un attributo definito da Microsoft? o uno dovrebbe definirlo da solo?
Mohammed Osman,

L'attributo [UniqueKey] è un attributo personalizzato che ho sviluppato per consentire l'aggiunta di chiavi uniche all'interno delle classi di entità .cs (e non tramite il metodo OnModelCreating () di DbContext)
Justin Tubbs,

3
È fantastico. Potresti per favore inserire il codice dell'attributo personalizzato che hai sviluppato ?!
Mohammed Osman,


2

Per qualcuno che sta provando tutte queste soluzioni ma non funziona prova questa, ha funzionato per me

protected override void OnModelCreating(ModelBuilder builder)
{

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

}

2

Per utilizzarlo nel core EF tramite la configurazione del modello

public class ApplicationCompanyConfiguration : IEntityTypeConfiguration<Company>
{
    public void Configure(EntityTypeBuilder<Company> builder)
    {
        builder.ToTable("Company"); 
        builder.HasIndex(p => p.Name).IsUnique();
    }
}

1

Nessuno di questi metodi ha funzionato per me in .NET Core 2.2, ma sono stato in grado di adattare un po 'di codice che avevo per definire una chiave primaria diversa per funzionare a questo scopo.

Nell'istanza seguente voglio assicurarmi che il campo OutletRef sia unico:

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

Ciò aggiunge l'indice univoco richiesto nel database. Ciò che non fa è fornire la possibilità di specificare un messaggio di errore personalizzato.


0

Possiamo aggiungere un indice chiave univoco usando API fluenti. Di seguito il codice ha funzionato per me

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

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

    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.