• LinkedIn - Círculo Negro
  • Facebook - Círculo Negro
  • Twitter - Círculo Negro
  • Instagram - Negro Círculo
  • YouTube - Círculo Negro
  • Keislene Ferreira

¿Cómo insertar o actualizar datos en CRM desde una fuente externa con SSIS?

Otro de los desafíos que me he topado recientemente ha sido el de insertar datos desde una fuente externa en CRM.


Las integraciones de plataformas son muy frecuentes, consultar datos, enviar, insertar, actualizar, eliminar, etc. Existen varias herramientas para hacer esto, por ejemplo, Kingswaysoft es una de las más potentes, pero cuando el presupuesto es acotado y el cliente no puede pagar por una licencia, la creatividad tiene que surgir y suplir las necesidades. Por ese motivo, me tocó utilizar SSIS directamente contra los servicios web de Dynamics 365 (on-premise) y acá estoy compartiendo la experiencia con ustedes.



Por un lado, tenemos una base de datos en SQL Server con la información que necesitamos introducir en CRM, por el otro el flamante Dynamics 365 on premise (el segundo que me toca instalar, configurar y personalizar desde la gran salida al mercado en diciembre de 2016).


Bueno, la pregunta era ¿qué uso? ¿un desarrollo en .Net, SSIS, algún truco de magia? Finalmente, me decidí por SSIS, ya que es una herramienta que usan mucho en el cliente y que yo ya había utilizado alguna vez, así que ahora era el momento de desempolvar los conocimientos de lo que en la universidad aprendí a llamar ETL y a aplicarlo para resolver la necesidad que había surgido.


Para empezar, utilicé Visual Studio 2012 con SQL Data Tools, creé un nuevo proyecto de Integration Services y seguí los siguientes pasos:





  1. Creé el nuevo paquete;

  2. Añadí el administrador de conexiones apuntando a la base de datos de SQL;

  3. Coloqué en el diseñador visual de mi paquete el control Data Flow Task;

  4. En el cuerpo de la Data Flow Task, coloqué el Data Flow component, conectado al Connector manager, seleccioné la tabla y las columnas necesarias;

  5. Utilicé el Sort component para ordenar los datos;

  6. Finalmente añadí un componente de Script, en el cual está toda la ciencia;

  7. Dentro del componente de script escribí mi código para tomar los datos y acceder al CRM.

La primera cosa que hice fue generar una variable de usuario a nivel del paquete para poder trabajar con la cadena de conexión de CRM, y seguidamente la añadí al componente:



A esa variable la uso internamente para poder conectarme al CRM al momento de iniciar los trabajos del script, la defino en el ámbito de la clase y la inicializo en el método "PreExecute":

using System; using System.Data; using System.Linq; using Microsoft.SqlServer.Dts.Pipeline.Wrapper; using Microsoft.SqlServer.Dts.Runtime.Wrapper; using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Client; using Microsoft.Xrm.Tooling; using Microsoft.Xrm.Tooling.Connector;

public class ScriptMain : UserComponent {

CrmServiceClient crmConn = null;

public override void PreExecute() { base.PreExecute();

string crmConnectionString = this.Variables.CrmConnectionString;

if (!String.IsNullOrEmpty(crmConnectionString)) { crmConn = new CrmServiceClient(crmConnectionString); } }

public override void PostExecute() { base.PostExecute();

crmConn.Dispose(); }

Para conectarme a CRM utilizo el CrmServiceClient de Xrm.Tooling de Dynamics 365. Para esto, añadí las referencias desde el SDK de CRM (acá no vale trabajar con los paquetes de NuGet).


¡Ah! ¡Muy importante! Para que funcione, hay que registrar las dlls necesarias del SDK de CRM en la GAC del servidor donde corre el SSIS.


Luego internamente, como estoy trabajando con la entidad "Cuenta" con un número de identificador fiscal único por cada cuenta, debo verificar si ya existe, si existe, debo actualizar el registro, si no existe, debo crearlo, eso lo hago en el método ProcessInputRow:

public override void Input0_ProcessInputRow(Input0Buffer Row) { string fiscalNumber = !Row.FiscalNumber_IsNull ? Row.FiscalNumber.Trim() : String.Empty; Guid existingAccountId = Guid.Empty;

if (!String.IsNullOrEmpty(fiscalNumber)) { //Si la cuenta no existe


if (!AccountAlreadyExistsInCRM(fiscalNumber, out existingAccountId)) { //Creo la cuenta Entity account = new Entity("account");

account["name"] = !Row.Name_IsNull ? Row.Name : String.Empty; account["description"] = !Row.Description_IsNull ? Row.Description.ToString() : String.Empty; account["emailaddress1"] = !Row.EMailAddress1_IsNull ? Row.EMailAddress1 : String.Empty; account["emailaddress2"] = !Row.EMailAddress2_IsNull ? Row.EMailAddress2 : String.Empty; account["emailaddress3"] = !Row.EMailAddress3_IsNull ? Row.EMailAddress3 : String.Empty; account["telephone1"] = !Row.Telephone1_IsNull ? Row.Telephone1 :String.Empty; account["telephone2"] = !Row.Telephone2_IsNull ? Row.Telephone2 :String.Empty; account["telephone3"] = !Row.Telephone3_IsNull ? Row.Telephone3 :String.Empty; account["fax"] = !Row.Fax_IsNull ? Row.Fax : String.Empty; account["address1_line1"] = !Row.Address1Line1_IsNull ? Row.Address1Line1 : String.Empty; account["address1_line2"] = !Row.Address1Line2_IsNull ? Row.Address1Line2 : String.Empty; account["address1_line3"] = !Row.Address1Line3_IsNull ? Row.Address1Line3 : String.Empty; account["address1_postalcode"] = !Row.Address1PostalCode_IsNull ? Row.Address1PostalCode.ToString() : String.Empty;

Guid accountId = crmConn.OrganizationServiceProxy.Create(account); } else //Si la cuenta ya existe { Entity account = new Entity("account"); account.Id = existingAccountId;

account["name"] = !Row.Name_IsNull ? Row.Name : String.Empty; account["description"] = !Row.Description_IsNull ? Row.Description.ToString() : String.Empty; account["emailaddress1"] = !Row.EMailAddress1_IsNull ? Row.EMailAddress1 : String.Empty; account["emailaddress2"] = !Row.EMailAddress2_IsNull ? Row.EMailAddress2 : String.Empty; account["emailaddress3"] = !Row.EMailAddress3_IsNull ? Row.EMailAddress3 : String.Empty; account["telephone1"] = !Row.Telephone1_IsNull ? Row.Telephone1 :String.Empty; account["telephone2"] = !Row.Telephone2_IsNull ? Row.Telephone2 :String.Empty; account["telephone3"] = !Row.Telephone3_IsNull ? Row.Telephone3 :String.Empty; account["fax"] = !Row.Fax_IsNull ? Row.Fax : String.Empty; account["address1_line1"] = !Row.Address1Line1_IsNull ? Row.Address1Line1 : String.Empty; account["address1_line2"] = !Row.Address1Line2_IsNull ? Row.Address1Line2 : String.Empty; account["address1_line3"] = !Row.Address1Line3_IsNull ? Row.Address1Line3 : String.Empty; account["address1_postalcode"] = !Row.Address1PostalCode_IsNull ? Row.Address1PostalCode.ToString() : String.Empty;

crmConn.Update(account); } } }

Un temita más es que para poder hacer debug del código, se debe colocar que se compile en 32-bit y no en 64.


También otro tema, no menor, es que debemos usar late-binding para trabajar en este entorno, ya que, por una causa que desconozco, no es posible usar early-binding.


Algo bueno, es que se puede usar LINQ, eso fue lo mejor, jaja. Lo hice al buscar la cuenta por identificador fiscal, como se muestra a continuación:

private bool AccountAlreadyExistsInCRM(string fiscalNumber, out GuidaccountId) { bool result = false; accountId = Guid.Empty;

if (crmConn != null) { using (OrganizationServiceContext svcContext = newOrganizationServiceContext(crmConn.OrganizationServiceProxy)) { var accounts = from account in svcContext.CreateQuery("account") where account["fiscalid"] == fiscalNumber.ToString() select account;

foreach (var item in accounts) { accountId = item.Id; result = true;

break; }

accounts = null; } }

return result; }

Bueno, espero que les sirva en sus proyectos de integración este humilde aporte.


¡Hasta el próximo post!



  • LinkedIn - Gris Círculo
  • Facebook - Gris Círculo
  • Twitter - Gris Círculo
  • Instagram - Gris Círculo
  • YouTube - Gris Círculo

Expertos en Microsoft Dynamics 365 y Power Platform

Copyright © 2020 AMGBS. Todos los derechos reservados.