Cómo paginar consultas .NET en Dynamics 365

Al extender funcionalidades de Dynamics, es probable tener que recorrer listados enormes de registros para hacer acciones recurrentes. Para ello, se realizan consultas Retrieve Multiple que, por defecto, están limitados a 5.000 registros -aunque pueden modificarse-. La cuestión es: ¿Cómo poder recorrer todos los registros con una sola consulta? ¿Cómo saber que los lotes son íntegros con registros distintos? Vayamos por partes.

La consulta

Una petición de Retrieve Múltiple es harta conocida y sencilla. Basta tener la instancia del servicio y la query a consultar:

var myQuery = new QueryExpression("entitylogicalname")
{
    // Contenido: filtros, condiciones, attributos, etc.
};

var retrievedRecords = service.RetrieveMultiple(myQuery);

En la response se encontrarán los registros pero sólo hasta el número máximo permitido para ese entorno. Siempre que trabajemos con entidades con pocos registros (entidades maestras, de configuración, categorías, tipos, etc.), no habrá problema.

¿Y si son muchos registros?

Lo obvio: una respuesta siempre devolerá registros. Nada más. No posee una configuración para saber cuales son los siguientes registros para una misma consulta. Por tanto, la estrategia no es pensar en cómo gestionar la respuesta sino la petición.

Una QueryExpression acepta introducir información adicional que, debidamente programada, podrá permitir una solicitud recurrente. En otras palabras, hacer el paginado. ¿Cuáles son esas propiedades? Pues básicamente una: PageInfo que, a su vez, contendrá la PageNumber y PagingCookie.

Sabiendo cómo se configura la query, ya es sólo cuestión de pensar cómo programarlo para que esté constantemente recorriendo todos los registros. Lo que se traduce en el siguiente código:

int PageNumber = 1;  // La página por defecto a buscar.
int PageSize = 5000; // Registros por paginado.
string PagingCookie = string.Empty;
RetrieveMultipleResponse retrieveResponse;            

// Se instancia la petición con los detalles se necesiten.
QueryExpression qe = new QueryExpression();

do
{
    // Esta parte configura la siguiente petición de paginado si procede.
    if ( pageNumber != 1 )
    {
        qe.PageInfo.PageNumber = pageNumber;
        qe.PageInfo.PagingCookie = pagingCookie;
    }

    // La ejecución de la petición en sí.
    RetrieveMultipleRequest retrieveRequest = new RetrieveMultipleRequest();
    retrieveRequest.Query = qe;
    retrieveResponse = (RetrieveMultipleResponse)service.Execute(retrieveRequest);

    retrieveResponse.EntityCollection.Entities.ToList().ForEach(r => 
    {
        // Las acciones a realizar sobre los registros obtenidos.
    });

    // La parte que comprueba si hay que realizar más peticiones.
    if ( retrieveResponse.EntityCollection.MoreRecords )
    {
        // Configura las variables que modificarán la query.
        pageNumber++;
        pagingCookie = retrieveResponse.EntityCollection.PagingCookie;
    }

// Control que finaliza la búsqueda cuando ya no hay más registros.
} while ( retrieveResponse.EntityCollection.MoreRecords );

¡Y voilà! Una manera sencilla de paginar registros. Ya sólo falta comprobar cómo adaptar el paginado a las necesidades funcionales concretas -si necesita control de errores, si tienen que aplicarse operación en bloques de varios registros o lo que sea-.

Resumiendo

  • Recorrer grandes lotes de registros es una tarea muy cotidiana en Dynamics.
  • Para ello contamos con configurar la QueryExpression y emplear RetrieveMultipleRequest.
  • Se añade el snippet comentado y queda el paginado construido.

Leave a comment