1. ¿Qué es?

Es un ORM (Object-Relational Mapper).

  • Función: Actúa como un traductor entre tu código C# (Clases y Objetos) y la Base de Datos (Tablas y Filas).

  • Diferencia con PHP: En lugar de escribir SQL a mano (SELECT * FROM...), manipulas objetos en C# y EF Core escribe el SQL por ti.

  • Filosofía: Usamos el enfoque “Code First” (primero escribes el código C# y la base de datos se crea a partir de él).


2. Los 3 Pilares Fundamentales

Para que funcione, necesitas estas tres piezas clave:

A. La Entidad (Entity)

Es una clase normal de C# que representa una Tabla de la base de datos.

  • Ubicación: src/UserApi.Web/Models/User.cs

  • Regla: Debe tener una propiedad Id (clave primaria).

C#

public class User 
{
    public int Id { get; set; } // Primary Key automática
    public string FullName { get; set; } // Columna varchar
}

B. El Contexto (DbContext)

Es la clase que representa la Sesión con la Base de Datos. Es el “puente” o gestor.

  • Ubicación: src/UserApi.Web/Data/AppDbContext.cs

  • Regla: Hereda de DbContext.

C#

public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
    // DbSet representa la tabla entera. 
    // Si no está aquí, EF Core no sabe que la tabla existe.
    public DbSet<User> Users { get; set; } 
}

C. La Configuración (Dependency Injection)

Debes “registrar” el Contexto en el contenedor de servicios para poder inyectarlo después.

  • Ubicación: src/UserApi.Web/Program.cs

C#

// Ejemplo usando base de datos en memoria (para desarrollo/tests)
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseInMemoryDatabase("NombreDeTuDB"));

3. Operaciones Principales (CRUD)

Lo más importante es que en .NET nunca bloqueamos el servidor. Todas las operaciones de base de datos deben ser Asíncronas (async/await).

AcciónCódigo EF CoreSQL Equivalente (Aprox)
Leer Todoawait context.Users.ToListAsync();SELECT * FROM Users
Leer Unoawait context.Users.FindAsync(id);SELECT * FROM Users WHERE Id = x
Filtrarawait context.Users.Where(u => u.Active).ToListAsync();SELECT * ... WHERE Active = 1
Insertarcontext.Users.Add(user);



await context.SaveChangesAsync();
INSERT INTO ...
Borrarcontext.Users.Remove(user);



await context.SaveChangesAsync();
DELETE FROM ...

⚠️ OJO: Add y Remove solo modifican la memoria. Nada se guarda en la base de datos real hasta que llamas a SaveChangesAsync().


4. Patrón de Uso Correcto (Arquitectura)

Nunca uses el DbContext directamente en el Controlador (Controller).

  • Mal: Controller DbContext

  • Bien: Controller Service DbContext

Esto permite desacoplar la lógica y facilita el Testing (como vimos con los Mocks).


5. Conceptos Avanzados que tocamos

  • In-Memory Database: Usamos Microsoft.EntityFrameworkCore.InMemory. Es volátil (se borra al reiniciar la API). Ideal para aprender y testing rápido sin instalar SQL Server.

  • Proyección (Select): No devuelvas la Entidad (User) al mundo exterior. Úsala para leer de la DB y conviértela a un DTO (UserDto) antes de responder.

    C#

    // Ejemplo de proyección manual
    var dtos = entities.Select(u => new UserDto(u.FullName, ...));
    

📝 Tu “Snippet” de código para Servicios

Cuando crees un servicio nuevo, esta es la plantilla mental que debes tener:

C#

public class MiServicio(AppDbContext context) : IMiServicio
{
    public async Task CrearAlgo(MiDto dto)
    {
        // 1. Convertir DTO -> Entidad
        var entidad = new MiEntidad { ... };
        
        // 2. Añadir al contexto
        context.MiTabla.Add(entidad);
        
        // 3. ¡Guardar cambios! (Vital)
        await context.SaveChangesAsync();
    }
}

validaciones_dto