Cómo crear un índice en Entity Framework 6.2 con código primero

112

¿Hay alguna manera de crear un índice en una propiedad / columna usando el código primero, en lugar de usar el nuevo IndexAttribute?

Valo
fuente
5
Un índice es un concepto de base de datos, no un concepto de modelo de entidad. Incluso si pudiera especificar un índice con un atributo oa través de la API fluida, en realidad no HACÍA nada en su aplicación. Solo sería una instrucción para que EF la use al crear la base de datos. Creo que tales instrucciones pertenecen a las migraciones de código primero, que están completamente relacionadas con la manipulación del esquema de la base de datos.
JC Ford

Respuestas:

84

Bueno, el 26.10.2017 Entity Framework 6.2 se lanzó oficialmente . Incluye la posibilidad de definir índices con facilidad a través de Fluent API. Ho es usar ya estaba anunció en la beta de 6.2.

Ahora puede usar el HasIndex()método, seguido de IsUnique()si debe ser un índice único.

Solo un pequeño ejemplo de comparación (antes / después):

// before 
modelBuilder.Entity<Person>()
        .Property(e => e.Name)
        .HasColumnAnnotation(
            IndexAnnotation.AnnotationName, 
            new IndexAnnotation(new IndexAttribute { IsUnique = true }));

// after
modelBuilder.Entity<Person>()
    .HasIndex(p => p.Name)
    .IsUnique();

// multi column index
modelBuilder.Entity<Person>()
    .HasIndex(p => new { p.Name, p.Firstname })
    .IsUnique();

También es posible marcar el índice como agrupado con .IsClustered().


EDITAR # 1

Se agregó un ejemplo de índice de varias columnas e información adicional sobre cómo marcar un índice como agrupado.


EDITAR # 2

Como información adicional, en EF Core 2.1 es exactamente igual que en EF 6.2 ahora.
Aquí está el artículo de MS Doc como referencia.

ChW
fuente
¡Esto es genial! Supongo que si tengo un índice de varias columnas sería algo como: .HasIndex (p => new {p.Name, p.Xyz})
Valo
Oh, lo siento, seguro. Debería serlo new. Yo lo arreglare.
ChW
¿Podría mostrarnos cómo podemos escribir el mismo código en Core 2.x?
user3417479
Hasta donde yo sé, debería ser el mismo código que se muestra en "después" y "índice de varias columnas".
ChW
87

Actualmente no existe un "soporte de primera clase" para crear un índice a través de la API fluida, pero lo que puede hacer es a través de la API fluida que puede marcar propiedades como atributos de la API de anotaciones. Esto le permitirá agregar el Indexatributo a través de una interfaz fluida.

A continuación, se muestran algunos ejemplos del elemento de trabajo del sitio de problemas para EF.

Cree un índice en una sola columna:

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(new IndexAttribute()));

Varios índices en una sola columna:

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(new[]
            {
                new IndexAttribute("Index1"),
                new IndexAttribute("Index2") { IsUnique = true }
            }));

Índices de varias columnas:

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty1)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName,
        new IndexAnnotation(new IndexAttribute("MyIndex", 1)));

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty2)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(new IndexAttribute("MyIndex", 2)));

El uso de las técnicas anteriores hará que las .CreateIndex()llamadas se creen automáticamente para usted en su Up()función cuando realice el scaffolding de su próxima migración (o se crearán automáticamente en la base de datos si no está usando migraciones).

Scott Chamberlain
fuente
4
que podría agregar el índice en la columna, pero no eliminará el índice agrupado creado en la clave principal. HasKey crea el índice agrupado en claves primarias que no se eliminan de forma predeterminada. Eso debe eliminarse explícitamente del archivo de migración creado al indicar clusered: false en el .Primarykey(x=>x.id,clustered:false)método
Joy
8
Probé el HasAnnotationmétodo y NO hay un método como este. pero encontré un método cuyo nombre HasColumnAnnotationacepta los parámetros que proporcionas. ¿Necesitas actualizar tu respuesta o me equivoco?
Hakan Fıstık
@HakamFostok Tomé el ejemplo directamente del sitio de EF. Quizás el nombre cambió en una de las versiones o hay un error tipográfico en la versión original.
Scott Chamberlain
3
Vea la parte inferior del siguiente enlace de una reunión de diseño a principios de este año: "Cambiar el nombre de HasAnnotation a HasColumnAnnotation (más otros lugares relevantes en la base del código)". entityframework.codeplex.com/…
Zac Charles
36

Creé algunos métodos de extensión y los envolví en un paquete nuget para hacer esto mucho más fácil.

Instale el EntityFramework.IndexingExtensionspaquete nuget.

Entonces puedes hacer lo siguiente:

public class MyDataContext : DbContext
{
  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    modelBuilder.Entity<Customer>()
        .HasIndex("IX_Customers_Name",          // Provide the index name.
            e => e.Property(x => x.LastName),   // Specify at least one column.
            e => e.Property(x => x.FirstName))  // Multiple columns as desired.

        .HasIndex("IX_Customers_EmailAddress",  // Supports fluent chaining for more indexes.
            IndexOptions.Unique,                // Supports flags for unique and clustered.
            e => e.Property(x => x.EmailAddress)); 
  }
}

El proyecto y el código fuente están aquí . ¡Disfrutar!

Matt Johnson-Pinta
fuente
Realmente me gusta el paquete, pero parece que el nombre del índice a veces falta después del scaffolding en el script up. Solo apareció para mí cuando usaba 4 o más propiedades en mi índice. Estoy trabajando con EF 6.1.3.
Mixxiphoid
@Mixxiphoid: ¿podría registrar el problema aquí con detalles de apoyo? También asegúrese de tener la versión 1.0.1, ya que hubo un error en la 1.0.0.
Matt Johnson-Pint
Tengo la versión 1.0.1. Registraré el problema, pero no puedo hacerlo en este momento.
Mixxiphoid
¿Cómo agrego el orden de las columnas participantes del índice a descendente? De forma predeterminada .HasIndex ("IX_Customers_EmailAddress", IndexOptions.Unique, ... crea un orden ascendente para todas las columnas participantes en el índice.
GDroid
@GDroid: desafortunadamente, esto no está expuesto por la IndexAttributeclase de EF , por lo que no puedo incluirlo en mi biblioteca.
Matt Johnson-Pint
24

Sin un nombre explícito:

[Index]
public int Rating { get; set; } 

Con un nombre específico:

[Index("PostRatingIndex")] 
public int Rating { get; set; }
Hugo Hilário
fuente
El índice parece estar depurado :(
Hamed Zakery Miab
1
@HamedZakeryMiab ¿Qué versión de Entity Framework estás usando? El índice no quedó obsoleto.
Hugo Hilário
disculpe, olvidé incluir EntityFramework. está incluido en ese ensamblaje. simplemente confundido acerca de la NS.
Hamed Zakery Miab
@HamedZakeryMiab, sí, ¡fue muy confuso! ¡Pensé que era parte de System.DataAnnotations! Definitivamente es el paquete de marco de entidad
AlbatrossCafe
3
la pregunta contiene la siguiente declaración instead of using the new IndexAttribute¿lo notó?
Hakan Fıstık
22

A partir de EF 6.1, [Index]se admite el atributo .
Utilizar [Index(IsUnique = true)]para índice único.
Aquí está el enlace de Microsoft

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

    [Index(IsUnique = true)] 
    [StringLength(200)] 
    public string Username { get; set; } 

    public string DisplayName { get; set; } 
}
Darie Dorlus
fuente
2
Si bien esto teóricamente puede responder a la pregunta, sería preferible incluir aquí las partes esenciales de la respuesta y proporcionar el enlace como referencia.
Enamul Hassan
@manetsus Muy bien. Agregué un fragmento de código para reflejar el cambio.
Darie Dorlus
3
La longitud de la cadena es necesaria; de lo contrario, verá una excepción "es de un tipo que no es válido para su uso como columna clave en un índice". Mi colega prefiere la solución modelBuilder en Conntext para que no abarrote su clase de usuario, que supongo que es válida.
Andrew Paté
¿Qué pasa con los índices con múltiples columnas para la singularidad? Es bastante común tener un índice de clave única de varias columnas ...
enormemente 76
1
@ Enorme76 Eso también es compatible. Para cada columna, necesitaría usar un atributo como el siguiente, [Index("IX_BlogIdAndRating", 2)] public int Rating { get; set; } [Index("IX_BlogIdAndRating", 1)] public int BlogId { get; set; } aquí la referencia de Microsoft
Darie Dorlus
8

Entity Framework 6

Property(c => c.MyColumn)
        .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_MyIndex")));

Y agregue usando:

using System.Data.Entity.Infrastructure.Annotations;
using System.ComponentModel.DataAnnotations.Schema;
Guilherme Ferreira
fuente
7

Puede utilizar la anotación de datos INDEX Code First Data Annotations

Emre
fuente
3
La longitud máxima de la clave es 900 bytes para nvarchar y 450 bytes para varchar. Si está utilizando código primero, las propiedades de la cadena serán nvarchar y debe incluir el atributo "StringLength" como en [[StringLength (450)]
dunwan
A partir de EF 6.1, esta es la respuesta correcta. docs.microsoft.com/en-us/ef/ef6/modeling/code-first/…
Chris Schaller
2

Si no desea utilizar atributos en sus POCO, siempre puede hacerlo de la siguiente manera:

context.Database.ExecuteSqlCommand("CREATE INDEX IX_NAME ON ..."); 

Puede ejecutar esta declaración en su DbInitializerclase derivada personalizada . Sin embargo, no conozco ninguna forma de Fluent API de hacer esto.

Mert Akcakaya
fuente
1
Claro, Mert. En este momento estoy usando migraciones y allí en el método Up () también puedes poner: CreateIndex ("dbo.Table1", "Column1", true, "Column1_IX") y en Down () DropIndex (("dbo.Table1 "," Column1_IX "). Solo esperaba que también agregaran una API fluida ...
Valo
1

Escribo un método de extensión para usarlo en EF fluido para evitar código adicional:

public static PrimitivePropertyConfiguration HasIndexAnnotation(
    this PrimitivePropertyConfiguration primitivePropertyConfiguration, 
    IndexAttribute indexAttribute = null
    )
{
    indexAttribute = indexAttribute ?? new IndexAttribute();

    return primitivePropertyConfiguration
        .HasColumnAnnotation(
            IndexAnnotation.AnnotationName, 
            new IndexAnnotation(indexAttribute)
        );
}

luego úsalo así:

Property(t => t.CardNo)
    .HasIndexAnnotation();

o así si el índice necesita algunas configuraciones:

Property(t => t.CardNo)
    .HasIndexAnnotation(new IndexAttribute("IX_Account") { IsUnique = true });
Omid-RH
fuente
1

Puedes usar uno de estos

// Índices

 this.HasIndex(e => e.IsActive)
            .HasName("IX_IsActive");

o

  this.Property(e => e.IsActive).HasColumnAnnotation(
            "Index",
            new IndexAnnotation(new IndexAttribute("IX_IsActive")));
Nayas Subramanian
fuente