Pular para o conteúdo
.NETModelos, DbContext e migrations
Módulo 03Construindo a Web API

Modelos, DbContext e migrations

intermediario 35 min de leitura·Atualizado · .NET 9
Resumo

Criamos as entidades do domínio (Categoria e Produto), o DbContext na camada de repositório, e geramos a migration inicial com dados de seed usando o EF Core.

1. Objetivos de Aprendizagem#

  • Modelar entidades com um relacionamento pai/filho.
  • Configurar o DbContext e o mapeamento via Fluent API.
  • Gerar migrations e semear dados iniciais.

2. Pré-requisitos#

  • Estrutura de camadas do tópico 17.1.

3. Conceito#

O EF Core é um ORM: mapeia classes C# para tabelas. O DbContext representa uma sessão com o banco e expõe DbSet<T> por entidade. Migrations versionam a evolução do schema como código. O porquê de manter isso na camada de repositório: infraestrutura não deve vazar para o domínio.

Modelo do curso: uma Categoria tem muitos Produtos (relacionamento 1:N).

4. Mão na Massa#

4.1. Setup#

Shell
dotnet add Catalog.Repository package Microsoft.EntityFrameworkCore.SqlServer
dotnet add Catalog.Api package Microsoft.EntityFrameworkCore.Design
dotnet tool install --global dotnet-ef   # se ainda não tiver

4.2. Implementação Passo a Passo#

  1. Entidades em Catalog.Entities/Models:
C#
namespace Catalog.Entities.Models;

public class Categoria
{
    public Guid Id { get; set; }
    public string Nome { get; set; } = default!;
    public ICollection<Produto> Produtos { get; set; } = new List<Produto>();
}

public class Produto
{
    public Guid Id { get; set; }
    public string Nome { get; set; } = default!;
    public decimal Preco { get; set; }
    public Guid CategoriaId { get; set; }
    public Categoria? Categoria { get; set; }
}
  1. DbContext em Catalog.Repository:
C#
using Catalog.Entities.Models;
using Microsoft.EntityFrameworkCore;

namespace Catalog.Repository;

public class RepositoryContext : DbContext
{
    public RepositoryContext(DbContextOptions<RepositoryContext> options) : base(options) { }

    public DbSet<Categoria> Categorias { get; set; } = default!;
    public DbSet<Produto> Produtos { get; set; } = default!;

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Produto>()
            .HasOne(p => p.Categoria)
            .WithMany(c => c.Produtos)
            .HasForeignKey(p => p.CategoriaId)
            .OnDelete(DeleteBehavior.Cascade);

        modelBuilder.Entity<Categoria>().HasData(
            new Categoria { Id = Guid.Parse("d2f1..."), Nome = "Periféricos" });
    }
}
  1. Registre no Program.cs:
C#
builder.Services.AddDbContext<RepositoryContext>(opts =>
    opts.UseSqlServer(builder.Configuration.GetConnectionString("SqlConnection")));
  1. appsettings.json:
JSON
{
  "ConnectionStrings": {
    "SqlConnection": "Server=localhost;Database=CatalogDb;Trusted_Connection=True;TrustServerCertificate=True;"
  }
}

4.3. Executando#

Shell
dotnet ef migrations add InitialCreate --project Catalog.Repository --startup-project Catalog.Api
dotnet ef database update --project Catalog.Repository --startup-project Catalog.Api

5. Exemplo Completo#

Registro do contexto via método de extensão:

C#
public static void ConfigureSqlContext(this IServiceCollection services, IConfiguration config) =>
    services.AddDbContext<RepositoryContext>(o =>
        o.UseSqlServer(config.GetConnectionString("SqlConnection")));

6. Boas Práticas e Armadilhas#

FaçaEvite
Definir chaves/relacionamentos via Fluent APIConfiar só em convenções para relacionamentos complexos
Usar valores fixos e determinísticos no HasDataUsar Guid.NewGuid() no seed (gera migrations instáveis)
Guardar a connection string fora do códigoComitar credenciais reais no appsettings.json
Atenção

DbContext é registrado como Scoped por AddDbContext. Nunca o injete em um Singleton — geraria captive dependency e não é thread-safe.

7. Segurança e Produção#

  • Connection strings de produção pertencem a user-secrets (dev) e variáveis de ambiente/secret store (prod), nunca ao repositório.
  • TrustServerCertificate=True é aceitável só em dev; em produção use certificados válidos.

8. Exercícios#

  • Fácil: adicione a propriedade Estoque (int) em Produto e crie uma nova migration.
  • Médio: semeie três produtos vinculados à categoria existente.
  • Desafio: troque DeleteBehavior.Cascade por Restrict e explique o impacto ao deletar uma categoria com produtos.

9. Resumo#

Modelamos Categoria/Produto, configuramos o RepositoryContext na camada de repositório e geramos migrations com seed determinístico. O DbContext fica isolado da apresentação.

10. Próximos Passos#

A seguir aplicamos o Repository Pattern e a Service Layer sobre esse contexto.

11. Referências#

17-02 — Modelos, DbContext e migrations | Curso ASP.NET Core