Conceito
Ao trabalhar com Code First, existem convenções que são feitas no EF. Mas, as vezes você pode desejar não seguir as convenções e fazer algo diferente. As duas maneiras são usando Annotations e FluentAPI.
Alguns exemplos de convenções são:
- Chave Primária: Propriedades chamadas
ID
ou<NomeDaClasse>Id
**são automaticamente configuradas como chaves primárias - Colunas: O EF Core cria colunas para todas as propriedades de uma classe de entidade com o mesmo nome da propriedade por padrão.
Mas, há cenários de mapeamento em que não podem ser alcançados usando Annotations. Por isso o FluentAPI é considerado um recurso mais avançado que o Data Annotations e vale ressaltar que ele usa o mesmo namespace ystem.ComponentModel.DataAnnotations
.
As diferenças são nas abordagens, uma vez que a decoração por atributos (Data Annotations) atua sobre classes que representam Models
e suas propriedades, enquanto o FluentAPI atua em um nível global, enunciando as regras diretamente no contexto da aplicação. **
Quando usar FluentAPI?
Podemos considerar utilizar o Fluent em cenários mais específicos, onde requer um controle mais fino sobre o mapeamento entre as entidades e o banco de dados. Geralmente é mais vantajoso em aplicações de grande porte ou de alta complexidade, onde as necessidades específicas de configuração vão além do que as Data Anotations podem oferecer.
- Em projetos onde o controle detalhado do mapeamento de entidades é essencial.
- Em sistemas com requisitos complexos de relacionamento, desempenho, conformidade ou personalização.
- Em aplicações empresariais que precisam de configurações avançadas de banco de dados e otimização.
Exemplos de aplicações
- Aplicações Empresariais Complexas: onde múltiplas entidades possuem modelos complexos e com um alto nível de inter-relacionamento e heranças. Pode ser necessário para configurar de forma detalhada índices compostos, heranças, propriedade sombreada, validações específicas etc. Tudo isso de forma centralizada e mantidas de forma coesa.
- Migrações de Sistemas Legados: Quando migramos uma aplicação legada para o EF Core, onde o schema do banco de dados existente deve ser mapeado cuidadosamente para novas classes de domínio.
- Aplicações com Processo de Negócios Personalizados: Sistemas que têm regras de negócios altamente personalizados, como plataforma de seguros, sistemas de planejamento de recursos empresariais (ERP) ou plataforma de gerenciamento de projeto complexo.
- Soluções Saas Personalizáveis: Software como serviço, onde os clientes exigem personalizações significativas em termos de estruturas de dados e comportamento do sistema. Por permitir a criação de dados flexível, diferentes clientes podem ter configurações diferentes, mas ainda assim, serem gerados de uma única base de código.
Além disso, há vários outros fatores não citados como: projeto de pesquisa e desenvolvimento, plataformas multitenancy ou multibanco, aplicações que precisam de alto desempenho.
ModelBuilder
No Entity Framework, a classe ModelBuilder atua como uma Fluent API. Usando essa classe, podemos configurar várias coisas diferentes.
O Entity Framework Core Fluent API configura os seguintes aspectos de um Model
:
Configuração do Model
Configura o mapeamento do Model
dos bancos de dados. Configura Schema padrão, funções do banco de dados, atributos adicionais de Data Annotation e entidades a serem excluídas do mapeamento.
Configuração da Entidade
Configura as tabelas da entidades e mapea os relacionamentos. PrimaryKey, AlternateKey, Index, table name, one-to-one, one-to-many, many-to-many relationships etc.
Configuração de Propriedade
Configura as propriedades do mapeamento da coluna. name, default value, nullability, Foreignkey, data type, concurrency column etc.
Podemos dizer que o FluentAPI é particulamente útil quando precisamos personalizar configurações que vão além das anotações de atributos nas classes, como por exemplo:
- Configurações avançadas de relacionamentos
- Configurações não suportadas por Data Annotation
- Configurações globais e reutilizáveis
- Definição de tipos de propriedade
- Validações complexas
Atributos
Os atributos servem para definir regras de validação, requisitos colunas de banco de dados (como tamanho de campo obrigatoriedade) e configurações de mapeamentos diretamente nas propriedades da classe de modelo.
Existem diversos atributos que pode ser adicionado em sua aplicação. Quanto mais você utilizar o Data Annotation, mais naturalmente você será capaz de conhecer e saber quais os tipos de atributos existentes. Vale ressaltar que você pode combinar múltiplos atributos em uma propriedade.
Atributos — Data Annotations vs. Fluent API
Data Annotations anotações são diretamente aplicadas às propriedades do modelo e são refletidas na estrutura da tabela do banco de dados quando as migrações são aplicadas. Elas são simples e diretas, mas podem se tornar difíceis de gerenciar em modelos complexos.
Fluent API oferece mais flexibilidade e centralização das configurações de mapeamento em um único local. É mais adequado para cenários complexos e para projetos em que você precisa de uma configuração mais refinada, como relacionamentos entre entidades ou configurações específicas do banco de dados.
Agora, para exemplificar vamos comparar dois exemplos para o mapeamento de um modelo Telefone
usando as duas abordagens e como elas serão refletidas no banco de dados:
1. Mapeamento usando Data Annotations
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Telefone
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(3, ErrorMessage = "O DDD deve conter 3 caracteres.")]
public string DDD { get; set; }
[Required]
[MaxLength(9, ErrorMessage = "O número do telefone deve ter no máximo 9 caracteres.")]
public string Numero { get; set; }
public int TipoTelefoneID { get; set; }
public int RestauranteID { get; set; }
public TelefoneTipo TelefoneTipo { get; set; }
public Restaurante Restaurante { get; set; }
}
Reflexo no Banco de Dados SQL:
Id: INT (chave primária)
DDD: VARCHAR(3), obrigatório
Numero: VARCHAR(9), obrigatório
TipoTelefoneID: INT.
RestauranteID: INT.
2. Mapeamento usando Fluent API
Modelo:
public class Telefone
{
public int Id { get; set; }
public string DDD { get; set; }
public string Numero { get; set; }
public int TipoTelefoneID { get; set; }
public int RestauranteID { get; set; }
public TelefoneTipo TelefoneTipo { get; set; }
public Restaurante Restaurante { get; set; }
}
Contexto com Fluent API:
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public DbSet<Telefone> Telefones { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Telefone>()
.HasKey(t => t.Id);
modelBuilder.Entity<Telefone>()
.Property(t => t.DDD)
.IsRequired()
.HasMaxLength(3)
.HasColumnName("DDD");
modelBuilder.Entity<Telefone>()
.Property(t => t.Numero)
.IsRequired()
.HasMaxLength(9)
.HasColumnName("Numero");
modelBuilder.Entity<Telefone>()
.Property(t => t.TipoTelefoneID)
.HasColumnName("TipoTelefoneID");
modelBuilder.Entity<Telefone>()
.Property(t => t.RestauranteID)
.HasColumnName("RestauranteID");
}
}
Reflexo no Banco de Dados SQL:
Id: INT (chave primária)
DDD: VARCHAR(3), obrigatório
Numero: VARCHAR(9), obrigatório
TipoTelefoneID: INT.
RestauranteID: INT
Top comments (0)