Bienvenidos a todos a un nuevo post dentro del curso de entity framework core en el que hoy vamos a ver las diferentes opciones que tenemos en entity framework core para cargar datos relacionados dependiendo de las necesidades de tu aplicación.
Índice
Recuerda que todo este código está disponible en GitHub, antes de continuar con este post, recomiendo mirar el de las relaciones en Entity Framework Core.
1 - Qué es Eager loading en entity framework core
Si bien es cierto que no hemos visto directamente qué es Eager loading, sí que lo hemos visto de forma indirecta. Ya que el Eager loading consiste en la carga directa (la verdad no se muy bien cómo traducir esto) de los datos que están relacionados con tu entidad en la misma consulta que consultamos la entidad principal.
En Entity framework Core esto se consigue cuando en el el dbSet
utilizamos un .Include()
:
[HttpGet("eager-loading")]
public async Task<List<User>> EagerLoading()
=> await _context.Users
.Include(a => a.Wokringexperiences)
.ToListAsync();
En este escenario, al cargar user estamos incluyendo las working experiences en la misma consulta, lo que en SQL se traduce en un join.
2 - Qué es lazy loading en entity framework core
Lazy loading o carga perezosa también lo vimos de pasada cuando explique IQueryable aqui es cuando cargamos una entidad principal cargada, pero los datos no se cargan hasta que accedemos a dicha propiedad de la entidad.
Antes de hacer el cambio en el código, tenemos que tener en cuenta que desde .netcore 3, tenemos que instalar el paquete Microsoft.EntityFrameworkCore.Proxies
dentro del proyecto, ya que ya no vienen por defecto.
En las opciones cuando incluimos el DBContext
debemos especificar la siguiente configuración:
services.AddDbContext<CursoEfContext>(options=>
options
.UseLazyLoadingProxies() // <----- HERE
.UseMySQL("server=127.0.0.1;port=4306;database=cursoEF;user=root;password=cursoEFpass"));
Y finalmente en la entidad, debemos especificarla como virtual:
public virtual ICollection<Wokringexperience> Wokringexperiences { get; set; }
Ahora sí, ya podemos ir a la lógica como tal, en nuestro caso, cambiamos el código al siguiente, y la parte donde consultamos las working experiences no se va a ejecutar hasta que llegamos a la línea donde accedemos a ella:
[HttpGet("lazy-loading/{userId}")]
public async Task<User?> LazyLoading(int userId)
{
User? user = await _context.Users.FirstOrDefaultAsync(a => a.Id == userId);
if (user is not null)
{
var experiences = user.Wokringexperiences; // <---- HERE
if (experiences is not null && experiences.Any())
{
Console.WriteLine("this user has experiences");
}
}
return user;
}
De primeras esta solución parece la mejor, pero hay que tener cuidado, ya que una consulta con un join, aunque tenga muchos registros, es muy posible que sea más rápida que muchas consultas pequeñas, así, qué, dependiendo lo que queramos o estemos haciendo, tendremos que tener cabeza a la hora de elegir Eager loading o Lazy loading.
Esto son las consultas que se ejecutan del código anterior:
- Nota: No confundir Lazy Loading de Entity framework core con
Lazy<T>
de .NET.
3 - Explicit loading en Entity Framework Core
Finalmente cuando hacemos explicit loading o carga explícita lo que hacemos es muy similar a lazy loading, ya que no cargamos los datos de forma automática, sino que tenemos que especificarlo de forma explícita.
Por ejemplo si cargamos un usuario, para cargar sus workingExperiences
lo hacemos de la siguiente forma:
[HttpGet("explicit-loading/{userId}")]
public async Task<User?> ExplicitLoading(int userId)
{
User? user = await _context.Users.FirstOrDefaultAsync(a => a.Id == userId);
if (user is not null)
{
await _context.Entry(user)
.Collection(a => a.Wokringexperiences)
.LoadAsync(); // <----- HERE
if (user.Wokringexperiences is not null && user.Wokringexperiences.Any())
{
Console.WriteLine("this user has experiences");
}
}
return user;
}
Como ves, estamos indicando la colección a la que hace referencia y posteriormente cargando los datos con el método Load()
/ LoadAsync()
. Igual que en el lazy loading, se hace una consulta separada.
Una cosilla a tener en cuenta es que Explicit loading se puede saltar el lazy loading cuando está deshabilitado (o no tenemos el proxy habilitado), así que te puede servir como hack en ciertos escenarios.
Conclusión
Como con todas las cosas en el desarrollo de software, la elección entre Lazy Loading, Eager Loading y Explicit Loading dependerá de tu situación y requerimientos particulares. Espero que este post te pueda ayudar a tomar una decisión!