Relacion entre datos cargados y entidad ImportFile

La funcionalidad que dispone CRM para importar archivos es bastante atractiva para los clientes que compran el producto. El poder cargar de modo automático grandes archivos de datos en la base de datos de CRM es una funcionalidad que se valora, sobre todo cuando el CRM es un sistema complementario a otros como podría ser un SAP, para tener los entornos alineados.

Lo único que es necesario configurar para automatizar la tarea de importación es un mapping de datos. Este mapping se tendrá que hacer con el primer archivo que se cargue y en él se indicará qué columnas del archivo Excel se cargarán en qué campos de la entidad de CRM. Posteriormente, el usuario de CRM únicamente tendrá que seleccionar el archivo que quiera importar y el mapping que se creó relativo a ese archivo. Como punto negativo únicamente decir que CRM admite de modo nativo importaciones de archivos con extensión CSV. Desde el propio Excel es relativamente sencillo exportar nuestro archivo con extensión .XLSX/.XLS a un archivo .CSV.

Desde el menú de Excel Guardar como podremos seleccionar la opción “CSV (delimitado por comas)” que nos generará el archivo con la estructura adecuada para Dynamics.

Exportar Excel como CSV

Exportar Excel como CSV

Para quien le interese el tema, si abrimos el archivo CSV con un editor de texto plano nos daremos cuenta que la estructura del propio archivo es muy simple, siendo la primera línea el nombre de las columnas separadas por punto y coma, y el resto los valores para cada columna, separados con el mismo carácter. Con esta estructura, no sería muy complicado escribir un programa que generase archivos CSV de cualquier base de datos, listos para importar en nuestro Dynamics.

Volviendo a la importación, una vez seleccionado el archivo y el mapping, el CRM empezará a cargar los datos. Nuestro trabajo terminaría aquí si únicamente nos interesase cargar los datos sin ningún tipo de procesado.
No obstante, no son pocos los clientes que se interesan por no solo cargar datos, sino también aplicarle algún tipo de lógica. Me viene a la mente por ejemplo una lógica de sustitución de un código cargado en el archivo por otro que esté ya en la base de clientes de CRM. O sencillamente relacionar cada registro cargado con un lookup a otra entidad mediante algún campo de identificación.

La idea de este post no es proponer una arquitectura de workflow o programa que aplique esta lógica puesto que en función de la cantidad de datos cargados se elegirá una u otra. El propósito de este post es descubrir de qué modo quedan relacionadas cada una de los registros creados en nuestra entidad con el archivo cargado.

Partimos por tanto de un dato conocido: el archivo cargado en la entidad ImportFile así como todos los datos asociados a él (número de líneas procesadas, fecha de inicio de carga, fecha de fin de carga, etc). Para complicarlo vamos a ponernos la restricción de que todos los archivos cargados van a la misma entidad. Sea cual sea el tipo de archivo se cargará en una entidad personalizada para la carga, escribiendo solo en unos campos en función del maping. El objetivo es conociendo únicamente el archivo de carga, obtener todos los registros creados en CRM a partir de él.

Logical name Schema name Label Type Descripción
importfileid ImportField Import Uniqueidentifier Id unico del registro
createdby CreatedBy Created By Lookup Usuario que cargo el file
completedon CompletedOn Completed On DateTime Fecha en la que se completó la importación
createdon CreatedOn Created On DateTime Fecha en la que se creó el registro
failurecount FailureCount Errors Integer Numero de lineas con error
partialfailurecount PartialFailureCount Partial Failures Integer Numero de lineas con error parcial
successcount SuccessCount Successes Integer Numero de lineas importadas correctamente
totalcount TotalCount Total Processed Integer Total de lineas (debería ser igual a la suma de los tres valores anteriores)
source Source Source String Nombre del file fuente
name Name Import Name String Nombre del registro en CRM. Coincide con el source
targetentityname TargetEntityName Target Entity String Entidad donde se cargarán los datos (en el ejemplo new_uploadentity)

Campos de la entidad ImportFile de CRM

Una primera idea sería obtener las fechas de inicio y final de carga del archivo y realizar un Retrieve Multiple de datos creados en ese intervalo de tiempo en nuestra entidad. Esta solución tiene un problema que es que funcionará siempre y cuando no se carguen dos –o más- archivos al mismo tiempo. Como lado positivo, esta es una query rápida que no requiere de joins y que si no mezclamos archivos al mismo tiempo obtiene buenos resultados.

Pero los usuarios no entienden de restricciones y si existe la posibilidad de importar files, seguro que más de una vez nos encontramos con que se solapan cargas. Para solucionar esto vamos a realizar una búsqueda de registros insertados en nuestra entidad partiendo del ID del archivo cargado.

Dynamics ha realizado un gran trabajo en este aspecto implementando un método de carga en paralelo a dos entidades. Por cada línea de nuestro archivo CSV se cargarán en CRM dos registros. El primero será siempre el registro que contiene la información de nuestros datos del Excel con el mapping aplicado en nuestra entidad de carga. Esta sería la importación misma. El segundo registro se almacena en la entidad ImportData. Este segundo registro no incluye información del archivo sino más bien información de la línea en bruto. Algunos datos que podemos encontrar en esta entidad son la posición de la línea en el file, los datos sin procesar de la línea o el ID de la línea en nuestra entidad de carga. Además en la entidad ImportData existe un campo lookup a la entidad ImportFile. El esquema de entidades sería el siguiente:

Relación entre entidad ImportFile, entidad ImportData y nuestra entidad de carga

Relación entre entidad ImportFile, entidad ImportData y nuestra entidad de carga

Como vemos, cuando cargamos un file se crea un registro en la entidad ImportFile que contiene la información de cabecera del file. En el proceso de importación, por cada línea del Excel se creará un registro en la entidad ImportData y otro registro en nuestra entidad de carga, en el esquema new_uploadentity.  El modo en que quedan relacionadas son que en el campo recordid del registro creado en ImportData  se incluye el id único del registro new_uploadentityId.

Ya tenemos todo para realizar la query y obtener los resultados. Las dos opciones que propongo son QueryExpression y Linq. Por mi parte recomiendo Linq puesto que no tiene la limitación de los 5000 registros recibidos.

En ambos casos la función nos devolverá los datos cargados en nuestra entidad new_UploadEntity dado el ID de un file de la entidad ImportFile.

En QueryExpression el código será similar a:

Si utilizamos Linq el código sería

En ambos casos he utilizado una clase de definición como la siguiente: