entity-framework-paginacion-skip-take

Paginación en Entity Framework usando `Skip` y `Take`

  • 3 min

En Entity Framework, podemos implementar paginación fácilmente usando los métodos Skip() y Take().

En aplicaciones que manejan grandes volúmenes de datos, recuperar todos los registros de una base de datos en una sola consulta puede no ser viable, porque costaría demasiado tiempo.

Por ejemplo, si cargamos 10.000 productos de un catálogo, sería muy lento. Además, el usuario no necesita (ni puede) ver 10.000 productos a la vez.

La paginación nos permite dividir los resultados en fragmentos manejables. Esto mejora la experiencia del usuario y, además, reduce el consumo de recursos.

¿Qué son Skip y Take?

Estos métodos pertenecen a LINQ y se utilizan para:

  • Skip(n): Omite los primeros n elementos de una consulta.
  • Take(m): Selecciona los siguientes m elementos después de saltar.

Juntos, permiten implementar paginación de forma muy sencilla.

Por ejemplo, si tenemos una tabla Productos con 100 registros y queremos mostrar 10 por página, la segunda página se obtendría con:

var pagina2 = dbContext.Productos
    .OrderBy(p => c.Id) 
    .Skip(10)  // Salta los primeros 10
    .Take(10)  // Toma los siguientes 10
    .ToList();

Implementación básica de paginación

Supongamos que queremos paginar una lista de clientes en una aplicación web. El código sería:

public List<Cliente> ObtenerClientesPaginados(int pagina, int registrosPorPagina)
{
    using (var context = new AppDbContext())
    {
        return context.Clientes
            .OrderBy(c => c.Nombre)  // ¡Importante ordenar!
            .Skip((pagina - 1) * registrosPorPagina)
            .Take(registrosPorPagina)
            .ToList();
    }
}
  • (pagina - 1) * registrosPorPagina calcula cuántos registros saltar.
  • Si pagina = 1, Skip(0) devuelve desde el primer registro.

Evitar Skip en grandes desplazamientos

En tablas con muchos (millones) de registros, Skip() puede ser lento. Esto se debe a que Skip debe recorrer todos los registros anteriores antes de omitirlos.

Para optimizar el rendimiento en estos casos, se pueden utilizar técnicas como:

  • Índices en columnas de ordenamiento: Asegúrate de que las columnas utilizadas en OrderBy estén indexadas.
  • Paginación basada en claves: En lugar de usar Skip, utiliza una condición Where basada en el último valor de la página anterior.

Por ejemplo, si estamos paginando productos por su ID:

int ultimoId = 10; // Último ID de la página anterior
int tamañoPagina = 10;

var productos = context.Productos
    .Where(p => p.Id > ultimoId)
    .OrderBy(p => p.Id)
    .Take(tamañoPagina)
    .ToList();