Listados de alto rendimiento
Vuelca un informe entero sin OFFSET con LoadAllRowsAsync: paginación por keyset, coste constante por página y sin filas repetidas.
Cuando necesitas todas las filas de un informe (exportar, reprocesar, sincronizar), la forma de paginar decide el rendimiento y la corrección. LoadAllRowsAsync, en DinaupReportBase, recorre el informe completo por keyset sobre el id, sin OFFSET.
El problema de OFFSET
La forma clásica de recorrer un informe página a página usa LIMIT/OFFSET:
await report.ExecuteQueryAsync(dinaupClient, 1, pageSize);
var filas = report.Rows.ToList();
while (await report.ExecuteQuery_NextPageAsync())
filas.AddRange(report.Rows);En volúmenes grandes tiene dos problemas:
- Corrección.
OFFSETsin un orden total y sin desempate no es determinista: el servidor puede devolver la misma fila en dos páginas o saltarse una. Si luego indexas por id (ToDictionary(r => r.Id)), obtienes una excepción de clave duplicada o, peor, filas que faltan sin avisar. - Rendimiento.
OFFSET 18000hace que el servidor recorra y descarte 18.000 filas en cada página. Cuanto más avanzas, más lento va: costeO(offset)por página.
La solución: keyset (cursor)
En vez de pedir "la página N", pides "las filas después del último id que vi":
WHERE id > :last_seen_id
ORDER BY id ASC
LIMIT :page_sizeCada página es un recorrido por rango de índice sobre la columna id: coste constante sin importar la profundidad y, como el id es único, nunca una fila repetida ni un hueco.
Cómo se usa
// Vuelca el informe entero, rápido y sin duplicados.
var todas = await report.LoadAllRowsAsync(dinaupClient, pageSize: 10000, adminMode: true);Eso es todo. El método:
- Ordena por la columna id del informe internamente. No llames a
AddOrder: lanza excepción si ya hay un orden definido. - Añade un único filtro
id > cursory lo avanza tras cada página, así que tus filtros (rangos de fecha, referencias…) se conservan y se combinan conAND. - Para cuando una página vuelve más corta que
pageSize, con guarda contra cursores estancados. - Si llega a
maxRowscon filas aún pendientes, lanza excepción en vez de devolver una lista truncada en silencio: reduce el informe con un filtro o subemaxRows.
Firma y valores por defecto:
Task<List<T>> LoadAllRowsAsync(
DinaupClientC dinaupClient,
int pageSize = 10000,
int maxRows = 50000000,
bool adminMode = false)¿Necesitas otro orden?
El keyset debe ordenar por id para funcionar, así que aplica el orden de presentación en memoria después:
var porFecha = todas.OrderBy(r => r.Fecha).ToList();Límites y excepciones
LoadAllRowsAsync lanza excepción cuando no puede garantizar un recorrido correcto:
| Condición | Excepción |
|---|---|
pageSize o maxRows no positivos | ArgumentException |
El informe no expone columna ID | InvalidOperationException |
Ya se llamó a AddOrder | InvalidOperationException |
Ya hay un filtro sobre la columna ID | InvalidOperationException |
Las filas no implementan IDinaupRow | InvalidOperationException |
Se alcanza maxRows con filas pendientes | InvalidOperationException |
Cuándo usar cada uno
ExecuteQuery_NextPageAsync (OFFSET) | LoadAllRowsAsync (keyset) | |
|---|---|---|
| Una página visible | ✅ mejor opción | excesivo |
| Volcar el informe entero | riesgo de duplicados/huecos, se ralentiza | ✅ rápido y correcto |
| Orden de presentación durante la paginación | ✅ en el servidor | ordena en memoria tras cargar |
El id se compara como texto en el servidor. El keyset solo es correcto si el servidor ordena el id y compara id > x con el mismo criterio textual y el mismo formato (minúsculas, con guiones). Es el comportamiento de las estructuras Dinaup estándar.
Para el resto de la API de informes (filtros, paginación clásica, tiempos del servidor), ver el Cliente Dinaup.