Como criar índice no Entity Framework 6.2 com código primeiro


112

Existe uma maneira de criar um índice em uma propriedade / coluna usando o código primeiro, em vez de usar o novo IndexAttribute?


5
Um índice é um conceito de banco de dados, não um conceito de modelo de entidade. Mesmo se você pudesse especificar um índice com um atributo ou por meio da API fluente, ele não faria nada em seu aplicativo. Seria apenas uma instrução para EF usar ao criar o banco de dados. Acredito que tais instruções pertencem a migrações de código-fonte, que se preocupam inteiramente com a manipulação do esquema do banco de dados.
JC Ford

Respostas:


84

Bem, 26.10.2017 Entity Framework 6.2 foi lançado oficialmente . Inclui a possibilidade de definir índices com facilidade via API Fluent. Como ele deve ser usado já foi anunciado na versão beta do 6.2.

Agora você pode usar o HasIndex()método, seguido de IsUnique()se deveria ser um índice exclusivo.

Apenas um pequeno exemplo de comparação (antes / depois):

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

Também é possível marcar o índice como agrupado com .IsClustered().


EDITAR # 1

Adicionado um exemplo de índice de várias colunas e informações adicionais sobre como marcar um índice como agrupado.


EDITAR # 2

Como informação adicional, no EF Core 2.1 é exatamente o mesmo que no EF 6.2 agora.
Aqui está o artigo do MS Doc como referência.


Isso é ótimo! Suponho que se eu tivesse um índice de várias colunas seria algo como: .HasIndex (p => novo {p.Name, p.Xyz})
Valo

Oh, desculpe, claro. Deve ser new. Eu irei consertar isso.
ChW

Você poderia mostrar como podemos escrever o mesmo código no Core 2.x?
user3417479

Pelo que eu sei, deve ser o mesmo código mostrado em "depois" e "índice de colunas múltiplas".
ChW

87

Atualmente não há "suporte de primeira classe" para a criação de um índice por meio da API fluente, mas o que você pode fazer é por meio da API fluente marcar propriedades como tendo atributos da API de anotação. Isso permitirá que você adicione o Indexatributo por meio de uma interface fluente.

Aqui estão alguns exemplos do item de trabalho do site de problemas da EF.

Crie um índice em uma única coluna:

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

Vários índices em uma única coluna:

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

Índices multicolunas:

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

O uso das técnicas acima fará com que as .CreateIndex()chamadas sejam criadas automaticamente para você em sua Up()função quando você organizar sua próxima migração (ou sejam criadas automaticamente no banco de dados se você não estiver usando migrações).


4
isso pode adicionar o índice na coluna, mas não removerá o índice clusterizado criado na chave primária. O hasKey cria o índice clusterizado nas chaves primárias que não são removidas por padrão. Isso deve ser removido explicitamente do arquivo de migração criado declarando clusered: false in .Primarykey(x=>x.id,clustered:false)method
Joy

8
Eu tentei o HasAnnotationmétodo e não existe nenhum método como este. mas encontrei um método cujo nome HasColumnAnnotationaceita os parâmetros que você fornece. Você precisa atualizar sua resposta ou estou errado?
Hakan Fıstık de

@HakamFostok Peguei o exemplo diretamente do site da EF. Talvez o nome tenha mudado em uma das versões ou haja um erro de digitação na versão original.
Scott Chamberlain

3
Veja na parte inferior do seguinte link de uma reunião de design no início deste ano: "Renomear HasAnnotation para HasColumnAnnotation (mais outros locais relevantes na base de código).". entityframework.codeplex.com/…
Zac Charles

36

Criei alguns métodos de extensão e os envolvi em um pacote nuget para tornar isso muito mais fácil.

Instale o EntityFramework.IndexingExtensionspacote nuget.

Então você pode fazer o seguinte:

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

O projeto e o código-fonte estão aqui . Aproveitar!


Eu realmente gosto do pacote, mas parece que o nome do índice às vezes está faltando após o scaffolding no script up. Ele só apareceu para mim ao usar 4 ou mais propriedades em meu índice. Estou trabalhando com EF 6.1.3.
Mixxiphoid de

@Mixxiphoid - você poderia registrar o problema aqui com os detalhes de suporte? Certifique-se também de ter a versão 1.0.1, pois havia um bug em 1.0.0.
Matt Johnson-Pint

Eu tenho a versão 1.0.1. Vou registrar o problema, mas não posso fazer isso no momento.
Mixxiphoid

Como adiciono a ordem das colunas participantes do índice em ordem decrescente? Por padrão .HasIndex ("IX_Customers_EmailAddress", IndexOptions.Unique, ... cria uma ordem crescente para todas as colunas participantes no índice.
GDroid

@GDroid - Infelizmente, isso não foi exposto pela IndexAttributeclasse de EF , então não posso incluí-lo em minha biblioteca.
Matt Johnson-Pint

24

Sem um nome explícito:

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

Com um nome específico:

[Index("PostRatingIndex")] 
public int Rating { get; set; }

O índice parece estar depreciado :(
Hamed Zakery Miab

1
@HamedZakeryMiab Qual versão do Entity Framework você está usando? O índice não foi descontinuado.
Hugo Hilário

com licença, esqueci de incluir EntityFramework. está incluído nessa montagem. apenas confuso sobre o NS.
Hamed Zakery Miab

@HamedZakeryMiab sim, isso foi super confuso! Achei que fosse parte do System.DataAnnotations! É definitivamente o pacote de estrutura de entidade
AlbatrossCafe

3
a pergunta contém a seguinte afirmação instead of using the new IndexAttributevocê notou?
Hakan Fıstık

22

Do EF 6.1 em diante, o atributo [Index]é suportado.
Use [Index(IsUnique = true)]para um índice exclusivo.
Aqui está o link da Microsoft

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

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

    public string DisplayName { get; set; } 
}

2
Embora isso possa teoricamente responder à pergunta, seria preferível incluir as partes essenciais da resposta aqui e fornecer o link para referência.
Enamul Hassan

@manetsus Muito bem. Eu adicionei um trecho de código para refletir a mudança.
Darie Dorlus,

3
O comprimento da string é necessário, caso contrário, você verá uma exceção 'é de um tipo inválido para uso como coluna-chave em um índice'. Meu colega prefere a solução modelBuilder no Conntext para que você não atrapalhe sua classe de usuário, o que eu acho que é válido.
andrew pate

E quanto aos índices com várias colunas de exclusividade? É muito comum ter um índice de chave exclusiva com várias colunas ...
enorl76

1
@ enorl76 Isso também é compatível. Para cada coluna, você precisaria usar um atributo como o seguinte, [Index("IX_BlogIdAndRating", 2)] public int Rating { get; set; } [Index("IX_BlogIdAndRating", 1)] public int BlogId { get; set; } Aqui a referência da Microsoft
Darie Dorlus

8

Entity Framework 6

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

E adicione usando:

using System.Data.Entity.Infrastructure.Annotations;
using System.ComponentModel.DataAnnotations.Schema;


2

Se não quiser usar atributos em seus POCO, você sempre pode fazer da seguinte forma:

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

Você pode executar esta instrução em sua DbInitializerclasse derivada personalizada . Não conheço nenhuma forma de API fluente de fazer isso.


1
Claro, Mert. No momento estou usando migrações e lá no método Up () você também pode colocar: CreateIndex ("dbo.Table1", "Column1", true, "Column1_IX") e em Down () DropIndex (("dbo.Table1 "," Column1_IX "). Eu só esperava que eles adicionassem uma API fluente também ...
Valo

1

Escrevo um método de extensão para uso em EF fluente para evitar código extra:

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

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

então use-o assim:

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

ou assim se o índice precisar de algumas configurações:

Property(t => t.CardNo)
    .HasIndexAnnotation(new IndexAttribute("IX_Account") { IsUnique = true });

1

Você pode usar um destes

// Indexes

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

ou

  this.Property(e => e.IsActive).HasColumnAnnotation(
            "Index",
            new IndexAnnotation(new IndexAttribute("IX_IsActive")));
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.