Criar e configurar um modelo
O EF Core usa um modelo de metadados para descrever como os tipos de entidade do aplicativo são mapeados para o banco de dados subjacente. Esse modelo é criado usando um conjunto de convenções – heurísticas que buscam padrões comuns. Em seguida, o modelo pode ser personalizado usando atributos de mapeamento (também conhecidos como anotações de dados) e/ou chamadas para os ModelBuilder métodos (também conhecidos como API Fluente), em OnModelCreating, ambos substituirão a configuração executada por convenções.
A maioria das configurações pode ser aplicada a um modelo direcionado a qualquer armazenamento de dados. Os provedores também podem habilitar a configuração específica para um armazenamento de dados específico e também podem ignorar a configuração que não tem suporte ou não é aplicável. Para obter documentação sobre configuração específica do provedor, consulte a seção Provedores de banco de dados.
Dica
Veja os exemplos deste artigo no GitHub.
Usar a API fluente para configurar um modelo
Substituía o método OnModelCreating
no contexto derivado e use a API Fluente para configurar o modelo. Este é o método mais eficiente de configuração e permite que a configuração seja especificada sem modificação de suas classes de entidade. A configuração da API fluente tem a precedência mais alta e substituirá as anotações de dados e as convenções. A configuração é aplicada na ordem em que os métodos são chamados e, se houver conflitos, a chamada mais recente substituirá a configuração especificada anteriormente.
using Microsoft.EntityFrameworkCore;
namespace EFModeling.EntityProperties.FluentAPI.Required;
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
#region Required
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.IsRequired();
}
#endregion
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Dica
Para aplicar a mesma configuração a vários objetos no modelo, consulte a configuração em massa.
Configuração de agrupamento
Para reduzir o tamanho do método OnModelCreating
, toda configuração de um tipo de entidade pode ser extraída para uma classe separada implementando IEntityTypeConfiguration<TEntity>.
public class BlogEntityTypeConfiguration : IEntityTypeConfiguration<Blog>
{
public void Configure(EntityTypeBuilder<Blog> builder)
{
builder
.Property(b => b.Url)
.IsRequired();
}
}
Em seguida, basta invocar o método Configure
de OnModelCreating
.
new BlogEntityTypeConfiguration().Configure(modelBuilder.Entity<Blog>());
Aplicar todas as configurações em um assembly
É possível aplicar todas as configurações especificadas em tipos que implementam IEntityTypeConfiguration
em um determinado assembly.
modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);
Observação
A ordem na qual as configurações serão aplicadas é indefinida, portanto, esse método só deve ser usado quando a ordem não importar.
Usando EntityTypeConfigurationAttribute
em tipos de entidade
Em vez de chamar Configure
explicitamente, um EntityTypeConfigurationAttribute pode ser colocado no tipo de entidade de modo que o EF Core possa encontrar e usar a configuração apropriada. Por exemplo:
[EntityTypeConfiguration(typeof(BookConfiguration))]
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Isbn { get; set; }
}
Esse atributo significa que o EF Core usará a implementação especificada IEntityTypeConfiguration
sempre que o tipo de entidade Book
for incluído em um modelo. O tipo de entidade é incluído em um modelo usando um dos mecanismos normais. Por exemplo, criando uma propriedade DbSet<TEntity> para o tipo de entidade:
public class BooksContext : DbContext
{
public DbSet<Book> Books { get; set; }
//...
Ou registrando-o em OnModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Book>();
}
Observação
Os tipos EntityTypeConfigurationAttribute
não serão descobertos automaticamente em um assembly. Os tipos de entidades precisam ser adicionados ao modelo antes que o atributo seja descoberto nesse tipo de entidade.
Usar anotações de dados para configurar um modelo
Poderá também aplicar determinados atributos (conhecidos como Anotações de Dados) a classes e propriedades. As anotações de dados substituirão as convenções, mas serão substituídas pela configuração da API Fluente.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace EFModeling.EntityProperties.DataAnnotations.Annotations;
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
}
[Table("Blogs")]
public class Blog
{
public int BlogId { get; set; }
[Required]
public string Url { get; set; }
}
Convenções internas
O EF Core inclui muitas convenções de criação de modelos habilitadas por padrão. Encontre todas elas na lista de classes que implementam a interface IConvention. No entanto, essa lista não inclui convenções introduzidas por provedores de banco de dados e plug-ins de terceiros.
Os aplicativos podem remover ou substituir qualquer uma dessas convenções, bem como adicionar novas convenções personalizadas que aplicam a configuração para padrões que não são reconhecidos pelo EF prontos para uso.
Dica
O código mostrado abaixo vem de ModelBuildingConventionsSample.cs.
Remover uma convenção existente
Às vezes, uma das convenções internas pode não ser apropriada para seu aplicativo, caso em que pode ser removida.
Dica
Caso o modelo não use atributos de mapeamento (também conhecidos como anotações de dados) para configuração, todas as convenções com o nome terminando em AttributeConvention
poderão ser removidas com segurança para acelerar a construção do modelo.
Exemplo: não criar índices para colunas de chave estrangeira
Normalmente, faz sentido criar índices para colunas de FK (chave estrangeira) e, portanto, há uma convenção interna para isso: ForeignKeyIndexConvention. Observando o modelo exibição de depuração para um tipo de entidade Post
com relações com Blog
e Author
, podemos observar que dois índices são criados - um para o FK BlogId
e outro para o FK AuthorId
.
EntityType: Post
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
AuthorId (no field, int?) Shadow FK Index
BlogId (no field, int) Shadow Required FK Index
Navigations:
Author (Author) ToPrincipal Author Inverse: Posts
Blog (Blog) ToPrincipal Blog Inverse: Posts
Keys:
Id PK
Foreign keys:
Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade
Indexes:
AuthorId
BlogId
No entanto, os índices têm sobrecarga e nem sempre pode ser apropriado criá-los para todas as colunas de FK. Para conseguir isso, a ForeignKeyIndexConvention
pode ser removida ao construir o modelo:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Conventions.Remove(typeof(ForeignKeyIndexConvention));
}
Olhando para a exibição de depuração do modelo por Post
agora, vemos que os índices em FKs não foram criados:
EntityType: Post
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
AuthorId (no field, int?) Shadow FK
BlogId (no field, int) Shadow Required FK
Navigations:
Author (Author) ToPrincipal Author Inverse: Posts
Blog (Blog) ToPrincipal Blog Inverse: Posts
Keys:
Id PK
Foreign keys:
Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade
Quando desejado, os índices ainda podem ser criados explicitamente para colunas de chave estrangeira, usando o IndexAttribute ou com configuração em OnModelCreating
.
Modo de depuração
O modo de depuração do construtor de modelos pode ser acessada no depurador do seu IDE. Por exemplo, com o Visual Studio:
Ele também pode ser acessado diretamente do código, por exemplo, para enviar o modo de depuração para o console:
Console.WriteLine(context.Model.ToDebugString());
O modo de depuração tem um formulário curto e longo. O formulário longo também inclui todas as anotações, que podem ser úteis caso precise exibir metadados relacionais ou específicos do provedor. A exibição longa também pode ser acessada do código:
Console.WriteLine(context.Model.ToDebugString(MetadataDebugStringOptions.LongDefault));