DEV Community

Yuri Peixinho
Yuri Peixinho

Posted on

2 1 1

Fluent API

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:

  1. Chave Primária: Propriedades chamadas ID ou <NomeDaClasse>Id **são automaticamente configuradas como chaves primárias
  2. 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

  1. 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.
  2. 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.
  3. 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.
  4. 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; }
}
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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; }
}
Enter fullscreen mode Exit fullscreen mode

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");
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

While many AI coding tools operate as simple command-response systems, Qodo Gen 1.0 represents the next generation: autonomous, multi-step problem-solving agents that work alongside you.

Read full post

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs