entity-framework-carga-eager-lazy-explicita

Carga Eager vs Lazy en Entity Framework

  • 6 min

En Entity Framework, podemos controlar cómo queremos cargar los datos relacionados con una entidad.

En una base de datos relacional, las entidades están relacionadas entre sí mediante claves primarias y foráneas.

La carga de datos relacionados se refiere a cómo y cuándo se recuperan los datos de las entidades relacionadas en una consulta.

Por ejemplo, en una base de datos de una tienda en línea, podríamos tener una entidad Pedido que está relacionada con una entidad Cliente.

Cuando recuperamos un Pedido, es posible que también queramos obtener los datos del Cliente asociado.

Es muy frecuente que queramos obtener estos datos relacionados (de hecho, lo haremos contínuamente).

Sin embargo, la forma en la que lo hagamos puede tener un gran impacto en la velocidad y rendimiento de nuestra aplicación ⚡.

Estrategias de carga de datos relacionados

Entity Framework nos permite cargar las entidades relacionadas de tres maneras diferentes:

  1. Eager Loading: Carga todas las entidades relacionadas de una sola vez, en la misma consulta.
  2. Lazy Loading: Carga las entidades relacionadas solo cuando se accede a ellas.
  3. Explicit Loading: Carga las entidades relacionadas manualmente, cuando el desarrollador lo decide.

Como no podría ser de otra forma, cada una tiene sus ventajas y desventajas, y un escenario adecuado donde conviene usar una u otra.

Vamos a ver cada una de las estrategias en detalle.

Carga Eager

Eager Loading es una estrategia en la que todas las entidades relacionadas se cargan de una sola vez, junto con la entidad principal. Esto se logra utilizando el método Include en nuestras consultas LINQ.

Supongamos que tenemos las siguientes entidades:

public class Cliente
{
    public int ClienteId { get; set; }
    public string Nombre { get; set; }
    public ICollection<Pedido> Pedidos { get; set; }
}

public class Pedido
{
    public int PedidoId { get; set; }
    public DateTime Fecha { get; set; }
    public int ClienteId { get; set; }
    public Cliente Cliente { get; set; }
}

Si queremos recuperar un Cliente junto con todos sus Pedidos, podemos usar Eager Loading de la siguiente manera:

using (var context = new MiContexto())
{
    var cliente = context.Clientes
                         .Include(c => c.Pedidos)
                         .FirstOrDefault(c => c.ClienteId == 1);
}

En este ejemplo, Entity Framework generará una consulta SQL que recupera tanto el Cliente como sus Pedidos relacionados en una sola consulta.

Lazy Loading

Lazy Loading es una estrategia en la que las entidades relacionadas se cargan solo cuando se accede a ellas por primera vez. Esto significa que, inicialmente, solo se carga la entidad principal, y las entidades relacionadas se cargan bajo demanda.

Para habilitar Lazy Loading en Entity Framework, debemos asegurarnos de que nuestras propiedades de navegación estén marcadas como virtual:

public class Cliente
{
    public int ClienteId { get; set; }
    public string Nombre { get; set; }
    public virtual ICollection<Pedido> Pedidos { get; set; }
}

Luego, podemos recuperar un Cliente sin cargar sus Pedidos de inmediato:

using (var context = new MiContexto())
{
    var cliente = context.Clientes
                         .FirstOrDefault(c => c.ClienteId == 1);

    // Los Pedidos se cargarán solo cuando se acceda a ellos
    var pedidos = cliente.Pedidos;
}

En este caso, Entity Framework generará una consulta SQL para recuperar el Cliente, y luego, cuando accedamos a cliente.Pedidos, generará otra consulta para recuperar los Pedidos relacionados.

Explicit Loading

Explicit Loading es una estrategia en la que el desarrollador decide cuándo cargar las entidades relacionadas. Esto se hace manualmente utilizando el método Load en el DbContext.

Supongamos que queremos cargar los Pedidos de un Cliente solo cuando lo decidamos:

using (var context = new MiContexto())
{
    var cliente = context.Clientes
                         .FirstOrDefault(c => c.ClienteId == 1);

    // Cargamos los Pedidos explícitamente
    context.Entry(cliente)
           .Collection(c => c.Pedidos)
           .Load();
}

En este ejemplo, Entity Framework generará una consulta SQL para recuperar el Cliente, y luego, cuando llamemos a Load, generará otra consulta para recuperar los Pedidos relacionados.

¿Cuándo usar cada estrategia?

La pregunta más importante, es cuando usar cada una de estas estrategias. Empecemos viendo resumen de cada una de las estrategias.

CaracterísticaEager LoadingLazy LoadingExplicit Loading
Carga de datosTodos los datos relacionados se cargan de una vezLos datos relacionados se cargan bajo demandaLos datos relacionados se cargan manualmente
Número de consultasUna sola consultaMúltiples consultas (N+1)Múltiples consultas (bajo control)
RendimientoMejor cuando se necesitan todos los datosMejor cuando se accede a pocos datos relacionadosMejor cuando se necesita control total
Complejidad del códigoSimpleSimpleMás complejo

Ahora, veamos cuando conviene usar cada una de ellas, con sus ventajas y desventajas.

Eager Loading

Útil cuando sabemos que vamos a necesitar todos los datos relacionados desde el principio.

Por ejemplo, en una pantalla de detalles donde se muestran todos los datos de una entidad y sus relaciones.

  • Sobrecarga de datos: Si cargamos más datos de los necesarios, podemos terminar con un exceso de información en memoria, lo que puede afectar el rendimiento.

Lazy Loading

Útil cuando no estamos seguros de si necesitaremos los datos relacionados, o cuando solo accederemos a ellos en ciertas condiciones.

Por ejemplo, en una lista de entidades donde solo se cargan los detalles al hacer clic en un elemento.

  • Problemas de rendimiento: Si accedemos a muchas entidades relacionadas, podemos terminar con un gran número de consultas a la base de datos, lo que se conoce como el problema de “N+1 consultas”.

Explicit Loading

Útil cuando necesitamos un control total sobre cuándo y qué datos relacionados cargar.

Por ejemplo, en una aplicación compleja donde el rendimiento es crítico y queremos evitar cargas innecesarias.

  • Código más complejo: El código puede volverse más verboso y complejo, ya que debemos manejar manualmente la carga de las entidades relacionadas.
  • Mayor riesgo de errores: Al tener que manejar manualmente la carga de entidades, hay un mayor riesgo de errores y olvidos.

Mejores prácticas

  1. Aunque Eager Loading puede ser eficiente, usarlo en exceso o con relaciones muy grandes puede resultar en consultas demasiado y descargar demasiados datos.

  2. Por contra, con Lazy Loading puedes tener un problema de N+1 consultas ( ocurre cuando EF Core realiza una consulta adicional por cada entidad cargada). Asegúrate de no cargar relaciones innecesarias de forma implícita.