Escrito el 21/05/2024

Entity Frameword Core: Consultas

Para realizar consultas a la base de datos existen varias formas.

Crear un contexto

Primero que todo, se debe crear un contexto, eso se puede hacer con Dependecy Injectio o directamente dentro de un bloque using (para asegurar la correcta limpieza de memoria y recursos)

using(var context = new ApplicationDbContext() {
    // consultas a la base de datos
}

Confirmar creación-migraciones

Se puede chequear si la base de datos fué creada y si existen migraciones que ejecutar.

using(var context = new ApplicationDbContext() {
    // para asegurarse que la base de datos fué creada
    context.Database.EnsureCreated();
    // para chequear que no existen migraciones pendientes
    if (context.Database.GetPendingMigrations().Count() > 0)
         context.Database.Migrate();
}

Consultas

Listar todos los registros

using var context = new ApplicationDbContext();
var result = context.Books.ToList();

Crear un registro

using var context = new ApplicationDbContext();
context.Books.Add(new Book() { Name = "El principito" });
context.SaveChanges();

Listar un registro

using var context = new ApplicationDbContext();
var result = context.Books.First(); // dispara una excepción en caso de no encontrar nada
var result = context.Books.FirstOrDefault(); // devuelve null si no lo encuentra
var result = context.Books.First(12); // busca por la clave primaria de la tabla
var result = context.Books.Single(); // dispara una excepción en caso de no encontrar nada o existen más de un elemento
var result = context.Books.SingleOrDefault(); // devuelve null si no lo encuentra o existen más de un elemento

Filtrar

using var context = new ApplicationDbContext();
var result = context.Books.Where(x => x.Id == 123).FirstOrDefault();

Se puede agregar una condición que siempre será agregada a cualquier insulta sobre una tabla. Por ejemplo, cuando queremos hacer un soft delete

protected override void OnModelCreating(Model builder model builder) {
...
  modelBuilder.HasQueryFilter(a => !a.IsDeleted);

...
}

Actualizar

using var context = new ApplicationDbContext();
var books = context.Books.Where(x => x.Name.Contains("A")).ToList();
foreach(var book in books)
    book.Name = book.Name.Replace("A", "a");
context.SaveChanges();

Eliminar

using var context = new ApplicationDbContext();
var book = context.Books.First(12);
var result = context.Books.Delete(book);
context.SaveChanges();

Log SQL

Para ver el código sql de una consulta

public class ApplicationDbContext : DbContext {

    protected override void OnConfiguring(DbContextOptionBuilder options) {
        options.UserSqlServer("Server=./SqlServer;Database=BookStore;TrustServerCertificate=True;Trusted_Connection=True")
            .LogTo(Console.WriteLine, new []{ DbLoggerCategory.Database.Command.Name }, LogLevel.Information);
    }
}

Async

Muchos métodos tienen su versión Async que permiten trabajar asincrónicamente.

Ejecución diferida

Sólo se ejecuta la query a la base de datos cuando se necesitan los datos. Por ejemplo:

  • foreach
  • ToList
  • ToArray
  • ToDictionary
  • First
  • FirstOrDefault
  • Single
  • SingleOrDefault

Larga de datos relacionados

Carga Explicita

Relacionando datos en consultas separadas.

Carga Eager

Carga bajo demanda utilizando el método .Include(x => x.Authors) y .IncludeThen(x => x.Addresses) para cargar la tabla relacionada.

Carga Lazy

Carga diferida utilizando los propiedades de navegación (referencias entre objetos). Por ej:book.Authors.First().Name.