Microsoft Dynamics 365 Finance and Operations trae consigo todo un framework de gestión de datos que nos permite integrarnos con una base de datos en Azure SQL de forma totalmente estándar.
Este framework, nos permite exportar la información del ERP a una base de datos externa para realizar reporting (BYOD), de forma que podamos generar nuestros informes y cuadros de mando en Power BI sin necesidad de atacar a la base de datos del sistema (AxDB), pero…, ¿Qué pasa si lo que necesito es leer o realizar otro tipo de operaciones no permitidas por este framework contra una BD externa?
En este artículo os mostraré un helper que hemos desarrollado para realizar estas operaciones de forma sencilla utilizando para ello la librería System.Data.SqlClient.
La idea este helper es que sea reutilizable al máximo, permitiéndonos ejecutar queries contra cualquier tipo de tabla independientemente de la estructura de la misma.
Configuración del almacén de entidades
Lo primero que necesitamos es configurar la cadena de conexión de la base de datos, y para ello reutilizo la configuración que nos da el estándar desde el Workspace de Administración de datos.
Lo único que necesitamos hacer es crear un nuevo almacén de datos de tipo Azure SQL DB y pegar la cadena de conexión de nuestra base de datos. Una vez configurada la conexión, podemos pasar al código!
Vamos a hablar solo de algunos métodos importantes, el resto del código lo tenéis disponible en mi repositorio de GitHub para vuestro uso y disfrute :).
Conectar con Azure SQL a través de X++
Por supuesto, el primer paso será añadir la siguiente directiva using a nuestro código para poder utilizar la librería SQLClient.
1 |
using System.Data.SqlClient; |
Seguidamente tendremos en cuenta el constructor, al que le pasaremos un registro de la tabla DMFSourceName, este registro no es otro que la configuración del almacén de entidades que vimos en el paso anterior, y si la cadena de conexión es válida (utilizamos el método de validación que se utiliza desde el propio botón Validar), continuamos con la ejecución.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public static JATSqlClient construct(DMFSourceName _sourceName) { JATSqlClient sqlClient = new JATSqlClient(); DMFDataSource dataSource = DMFDataSource::find(_sourceName); int infologLine = infologLine(); if (DMFDataSource::validateEntityConnectionString(dataSource)) { infolog.clear(infologLine); sqlClient.dmfDataSource = dataSource; } else { throw Exception::Error; } return sqlClient; } |
Ahora vamos a hablar de los cuatro métodos principales de este helper, que son utilizados para leer, insertar, actualizar y eliminar registros en la base de datos de Azure SQL.
La base de estos métodos es la utilización de tablas temporales dentro del ERP que tendrán el mismo esquema que las tablas destino en la base de datos externa, de modo que, por ejemplo, en la inserción, lo que haremos es, desde el ERP generar todos los registros dentro de la tabla temporal, para, en última instancia, pasárselos al helper, el cual recorrerá esos registros y los generará en el destino.
Del mismo modo, en la lectura, recuperaremos desde el helper los datos almacenados en la base de datos de Azure, para luego recorrerlos e insertarlos dentro de nuestra tabla temporal. Esta tabla temporal será la que devolvamos desde nuestro helper a la lógica de negocio del ERP para facilitar el tratamiento de los datos en el mismo.
De este modo, y jugando con Common y las clases SysDictTable y SysDictField, habilitamos a nuestro helper para trabajar con cualquier tipo de tabla, sea cual sea su estructura, y así hacerlo totalmente reutilizable y genérico.
Aquí podemos ver el ejemplo de la inserción de datos utilizando las clases anteriormente mencionadas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
private str createInsertQuery(Common _common) { SysDictTable dictTable = new SysDictTable(_common.TableId); SysDictField dictField; FieldId fieldId = dictTable.fieldNext(0); str query = 'INSERT INTO %1 (%2) VALUES (%3)'; container conFields, conValues; while (fieldId) { dictField = dictTable.fieldObject(fieldId); if (dictField.isSql()) { conFields += dictField.name(); conValues += this.getSqlValue(_common.(fieldId), dictField.baseType()); } fieldId = dictTable.fieldNext(fieldId); } query = strFmt(query, tableId2Name(_common.TableId), con2Str(conFields, ', '), con2Str(conValues, ', ')); return query; } |
Este método, como podemos ver, se encarga de generar y devolver la sentencia SQL que será ejecutada posteriormente.
Conclusión
El objetivo de este post, no es mostrar todo el código utilizado, sino, explicar la base del mismo, para que se entienda su funcionamiento. Como antes indiqué, en el mi repositorio de GitHub podéis encontrar tanto la clase JATSQLClient, como la clase JATSQLTest, donde podéis ver un ejemplo de utilización.
Espero que os resulte útil, y como siempre, cualquier problema, sugerencia o mejora, no dudéis en contactar conmigo, estaré encantado de discutirlo 😊.
1 comment / Add your comment below