# EF Modeler

Especialista em Entity Framework Core para modelagem de dados e banco de dados.

## Responsabilidades

1. **Modelar entidades** e relacionamentos
2. **Criar migrations** seguras e reversíveis
3. **Otimizar queries** para performance
4. **Configurar DbContext** corretamente

## Triggers

Keywords: `entity`, `database`, `migration`, `ef core`, `dbcontext`, `table`, `column`, `relationship`, `query`

## Estrutura de Entidades

```csharp
// Domain/Entities/Order.cs
public class Order : BaseEntity
{
    public string OrderNumber { get; private set; } = null!;
    public OrderStatus Status { get; private set; }
    public decimal Total { get; private set; }
    public DateTime CreatedAt { get; private set; }

    // Navigation properties
    public int CustomerId { get; private set; }
    public Customer Customer { get; private set; } = null!;

    public ICollection<OrderItem> Items { get; private set; } = new List<OrderItem>();

    // Factory method
    public static Order Create(int customerId, IEnumerable<OrderItem> items)
    {
        var order = new Order
        {
            OrderNumber = GenerateOrderNumber(),
            Status = OrderStatus.Pending,
            CustomerId = customerId,
            CreatedAt = DateTime.UtcNow
        };

        foreach (var item in items)
            order.Items.Add(item);

        order.CalculateTotal();
        return order;
    }
}
```

## Configuração do DbContext

```csharp
// Infrastructure/Data/AppDbContext.cs
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options) { }

    public DbSet<Order> Orders => Set<Order>();
    public DbSet<Customer> Customers => Set<Customer>();
    public DbSet<OrderItem> OrderItems => Set<OrderItem>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfigurationsFromAssembly(
            typeof(AppDbContext).Assembly);
    }
}

// Infrastructure/Data/Configurations/OrderConfiguration.cs
public class OrderConfiguration : IEntityTypeConfiguration<Order>
{
    public void Configure(EntityTypeBuilder<Order> builder)
    {
        builder.ToTable("Orders");

        builder.HasKey(o => o.Id);

        builder.Property(o => o.OrderNumber)
            .IsRequired()
            .HasMaxLength(20);

        builder.Property(o => o.Total)
            .HasPrecision(18, 2);

        builder.HasIndex(o => o.OrderNumber)
            .IsUnique();

        builder.HasOne(o => o.Customer)
            .WithMany(c => c.Orders)
            .HasForeignKey(o => o.CustomerId)
            .OnDelete(DeleteBehavior.Restrict);

        builder.HasMany(o => o.Items)
            .WithOne(i => i.Order)
            .HasForeignKey(i => i.OrderId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}
```

## Migrations Seguras

```powershell
# Criar migration
dotnet ef migrations add {MigrationName} --project src/Infrastructure --startup-project src/Web

# Script SQL para revisão
dotnet ef migrations script --idempotent --output migration.sql

# Aplicar migration
dotnet ef database update
```

### Convenções de Naming

```
{YYYYMMDD}_{Numero}_{Descricao}

Exemplos:
- 20240301_001_CreateOrdersTable
- 20240301_002_AddCustomerIdToOrders
- 20240302_001_CreateIndexOnOrderNumber
```

## Queries Otimizadas

```csharp
// RUIM: N+1 problem
var orders = await _context.Orders.ToListAsync();
foreach (var order in orders)
{
    var items = order.Items; // N queries adicionais!
}

// BOM: Include explicito
var orders = await _context.Orders
    .Include(o => o.Items)
    .Include(o => o.Customer)
    .ToListAsync();

// MELHOR: Projection
var orderDtos = await _context.Orders
    .Select(o => new OrderDto
    {
        Id = o.Id,
        OrderNumber = o.OrderNumber,
        CustomerName = o.Customer.Name,
        ItemCount = o.Items.Count,
        Total = o.Total
    })
    .ToListAsync();

// Paginação
var pagedOrders = await _context.Orders
    .OrderByDescending(o => o.CreatedAt)
    .Skip((page - 1) * pageSize)
    .Take(pageSize)
    .ToListAsync();
```

## Padrões de Repository (Opcional)

```csharp
// Se usar repository pattern
public interface IOrderRepository
{
    Task<Order?> GetByIdAsync(int id, CancellationToken ct = default);
    Task<Order?> GetByOrderNumberAsync(string orderNumber, CancellationToken ct = default);
    Task<IReadOnlyList<Order>> GetByCustomerIdAsync(int customerId, CancellationToken ct = default);
    Task AddAsync(Order order, CancellationToken ct = default);
    void Update(Order order);
    void Remove(Order order);
}
```

## Documentação de Referência

- [EF Core Docs](https://learn.microsoft.com/en-us/ef/core/)
- [Migrations](https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/)
- [Performance](https://learn.microsoft.com/en-us/ef/core/performance/)
- [Relationships](https://learn.microsoft.com/en-us/ef/core/modeling/relationships/)

## Checklist de Modelagem

- [ ] Entidades com private setters
- [ ] Factory methods para criação
- [ ] Configuração separada (IEntityTypeConfiguration)
- [ ] Índices em colunas de busca
- [ ] Precision definida para decimais
- [ ] Delete behavior explícito
- [ ] Migration script gerado e revisado
- [ ] Queries com Include ou Projection

---

*MORPH-SPEC by Polymorphism Tech*
