Entity Framework Core agrega restricción de código único primero

152

No puedo encontrar la manera de agregar una restricción única a mi campo usando el atributo:

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

Estoy usando estos paquetes:

 "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
fuente
Las muestras de la API con fluidez para los índices se ven en learnentityframeworkcore.com/configuration/fluent-api/…
Michael Freidgeim

Respuestas:

301

En EF core no puede crear índices usando anotaciones de datos, pero puede hacerlo usando la API Fluent.

Así dentro de tu {Db}Context.cs:

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

... o si está utilizando la sobrecarga con buildAction:

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

Puede leer más sobre esto aquí: Índices

Sampath
fuente
1
Muchas gracias por su ayuda, ¡es la solución correcta!
Vadim M
En caso de que alguien llegue aquí buscando una solución que funcione cuando se usa el esquema de identidad de MS, sugiero establecer la restricción única en el campo NormalizedEmail, no en el correo electrónico (de la entidad AspNetUsers). El uso de un caso diferente podría no violar la restricción, incluso si se trata de la misma dirección de correo electrónico, dependiendo de la configuración de clasificación de la base de datos.
Tom
44
Este código no funciona para la columna de tipo cadena :( ¿Hay alguna forma de agregar una restricción única en la columna de cadena?
Johar Zaman
Ir a porHasAlternateKey
Chamika Sandamal
1
Intenté esto cuando estaba trabajando en esto, pero ahora no necesito implementar esto. Por cierto, gracias por tu comentario. @Sampath
Johar Zaman
70

Además, si desea crear restricciones únicas en varias columnas, simplemente puede hacerlo (siguiendo el enlace de @ 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
fuente
9

Solución para 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 tabla DB se verá así:

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

Ref. A los documentos de EF Core

Evgeniy Miroshnichenko
fuente
11
Según los documentos de 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
Referencia al comentario de bigworld12
granadaCoder
3

El OP pregunta si es posible agregar un atributo a una clase de entidad para una clave única. La respuesta corta es que ES posible, pero no es una característica lista para usar del Equipo Principal de EF. Si desea utilizar un atributo para agregar claves únicas a sus clases de entidad Entity Framework Core, puede hacer lo que he publicado aquí

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
fuente
El atributo [UniqueKey] es un atributo definido por Microsoft? o uno debería definirlo él mismo?
Mohammed Osman
El atributo [UniqueKey] es un atributo personalizado que he desarrollado para permitir la adición de claves únicas dentro de las clases de entidad .cs (y no a través del método OnModelCreating () de DbContext)
Justin Tubbs
3
Eso es genial. ¿Podría poner el código del atributo personalizado que desarrolló?
Mohammed Osman el
2

Para alguien que está probando todas estas soluciones pero no funciona, pruebe esta, funcionó para mí

protected override void OnModelCreating(ModelBuilder builder)
{

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

}
Shonie
fuente
2

Para usarlo en el núcleo de EF a través de la configuración del modelo

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

Ninguno de estos métodos funcionó para mí en .NET Core 2.2, pero pude adaptar parte del código que tenía para definir una clave principal diferente para este propósito.

En la siguiente instancia, quiero asegurarme de que el campo OutletRef sea único:

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

Esto agrega el índice único requerido en la base de datos. Sin embargo, lo que no hace es proporcionar la capacidad de especificar un mensaje de error personalizado.

Robin Wilson
fuente
0

Podemos agregar un índice de clave único utilizando una API fluida. El siguiente código funcionó para mí

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
fuente