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.
O que é Data Annotation
Usamos Data Annotation para validação de dados dos nossos Models
, além disso, definem regras de requisitos de bancos de dados e outras configurações de mapeamento diretamente no código do modelo. Ao colocar os decoradores antes do atributo desejado, é adicionado um comportamento que permite o .NET runtime executar esses processamentos adicionais que possibilitam a validação dos campos, propriedades e classes.
public class Order
{
[Key]
public int OrderID { get; set; }
[Required(ErrorMessage = "CustomerName is required")]
[StringLength(100, ErrorMessage = "CustomerName cannot be longer than 100 characters")]
public string CustomerName { get; set; }
[RegularExpression(@"^\d+.?\d{0,2}$", ErrorMessage = "Invalid total")]
[Range(1, 500, ErrorMessage = "Total must be between 1 and 500")]
public decimal Total { get; set; }
}
- A annotation
[Key]
é colocada na propriedadeOrderID
, que marca como identificador único - A annotation
[Required]
e[StringLength]
colocada na propriedadeCustomerName
garante que o campo não fique vazio e que não ultrapasse 100 caracteres. - A annotation
[RegualarExpression]
e[Range]
no campoTotal
força uma validação específica de números
Vantagens e Desvantagens
Vantagens
- Simplicidade: Fáceis de entender e aplicar, tornam o código mais legível e intuitivo, principalmente para quem está começando
- Integração com ASP NET MVC: Por ser altamente integradas com o ASP NET MVC, elas são automaticamente utilizadas nas validações do lado do servidor e cliente em formulários
- Menos código: Por serem declarativas, podem reduzir a quantidade de código boilerplate necessário para definir regras de validação
Desvantagens
- Limitação em Complexidade: Em cenários complexos onde é preciso maior controle como as entidades são mapeadas para o bancos de dados, podem ser insuficientes. Por exemplo, relacionamento complexos entre entidades, chaves compostas ou configurações específicas de colunas.
- Mistura de Preocupações e Responsabilidades: Pode misturar as preocupações e responsabilidades de mapeamento de banco de dados com a lógica do negócio, que leva um acoplamento indesejado entre essas camadas.
-
Dificuldade em Manter e Escalar: Em projetos grandes, onde as entidades possuem muitas proriedades e relações complexas, usar Data Annotation pode levar a um modelo (
model
) difícil de manter. Todas as regras de validação e mapeamento são embutidas no modelo, o que pode dificultar a manutenção e evolução do código.
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)