Personalizar la Virtualización

<< Click to Display Table of Contents >>

Navigation:  Bizagi Studio > Asistente de Procesos > Modelar Datos > Conexiones con fuentes de datos externas > Virtualización de datos > Utilizar la configuración avanzada de Virtualización >

Personalizar la Virtualización

 

Resumen

Bizagi presenta el Asistente el cual le ayudará en la configuración de la conexión de una base datos externa SQL Server u Oracle (para integración a nivel de datos).

 

Para otra fuente de datos diferente a SQL Server y Oracle, se puede sobrescribir los métodos y clases utilizado por Bizagi en la virtualización.

 

 

¿Qué se debe hacer?

Para poder utilizar la Virtualización de Bizagi con una fuente de datos externa diferente a SQL Server u Oracle se debe seguir los siguientes pasos:

 

1. Crear una librería de Virtualización

A través de una librería personalizada, usted podrá sobrescribir las clases y métodos de la virtualización de Bizagi (como se describe en la siguiente sección: Sobrescribir de métodos y clases).

 

2. Configurar el proveedor de datos de Bizagi para utilizarlo en la librería personalizada de Virtualización.

Esta configuración utiliza la configuración avanzada de Bizagi para virtualizaciones.

 

 

Sobrescribir de Clases y Métodos

Para personalizar la virtualización de Bizagi, es necesario desarrollar un componente que implemente las interfaces:

IProviderVirtualDA2

IEntityVirtualDA

IParameter

IDatabaseConstants

 

 

Bizagi separa la operación de conectar, desconectar y administración transaccional de la operación de la búsqueda de datos desde el proveedor de datos externos y de las interfaces de la entidad. Es decir, cuando se crea una librería de virtualización personalizada, Bizagi sigue las mejores prácticas para la gestión y diseño de la implementación.

 

 

Interfaz del proveedor: IProviderVirtualDA2

La clase que invoca la interfaz debe contener los siguientes métodos:

 

void Init (Dictionary<string, string> metadata): A cargo de tomar la información suministrada, como el nombre del servidor, el nombre de la base de datos, usuario, contraseña, etc. La clase recibe el objeto Dictionary<string, string>, el cual contiene los datos configurados como metadata del sistema.

void OpenConnection(): Este método es utilizado para realizar la conexión con el sistema externo. En el caso de una base de datos, el método construye los enlaces de la conexión y abre la conexión con el repositorio.

void CloseConnection(): A cargo de cerrar la conexión con el sistema de datos externos.

void BeginTransaction(): A cargo de iniciar una nueva transacción para la operación actual del sistema.

void Commit(): Realizar commit de la transacción actual en el sistema de referencia.

void Rollback(): Realizar un rollback (regresar al estado inicial) de la transacción actual del sistema de referencia.

DataSet RunQuery(string sQuery, string sTableName): Este método se utiliza desde las formas para ejecutar la consultar en la fuente.

void ClearParameters(): A cargo de limpiar el arreglo que contenga parámetros de una anterior invocación.

void AddParameter(Vision.DA.IParameter oParameter): A cargo de cargar un parámetro para la invocación.

Vision.DA.IParameter CreateParameterObject (string sParameterName, Vision.Defs.EDataType eDataType, int iSize, object oValue): A cargo de crear el objeto que contiene los parámetros.

 

Interfaz del proveedor: ICustomQueryDA

La clase que invoca la interfaz debe contener los siguientes métodos:

 

void AddParameter (string parameterName, BizagiDataType dataType, int size, byte precision, byte scale, object value, ParameterDirection parameterDirection): A cargo de adicionar parámetros al query que será ejecutado.

void ClearParameters(): Elimina los parámetros presentes en el query.

DataSet RunQuery(string query, string tableName): se usa para consultar los valores de la funte de datos externa. La lógica es equivalente ahacer unquery sobre los campos del objeto.

 

Interfaz de la entidad: ICustomVirtualizationDA

La clase que implementa esta interfaz debe contener la lógica necesaria para manipular la información virtualizada, como insertar un registro nuevo, consultar dentro de un grupo de registros, modificar y eliminar un registro.

Los métodos que esta clase debe tener se listan a continuación:

 

void Init(ICustomProviderDA provider): Inicia la conexión con el sistema.

 

Parámetros

Descripción

provider

Permite convertir el objeto que invoca la interfaz

ICustomProviderDA.

 

 

DataSet GetEntity(string entitySource, KeyColumn[] keyColumns, string[] columnList): Utilizado como consulta de los valores de la fuente de datos externa. Esto es equivalente a realizar una consulta en los campos del objeto sin tener que aplicar filtros.

 

Parámetros

Descripción

entitySource

Nombre de la tabla a replicar en la fuente de datos

keyColumns

Arreglo que contiene el nombre de las columnas de la consulta en la fuente de datos.

columnList

Arreglo que contiene el nombre de las columnas a consultar

RETURNED DataSet

Un DataSet con los valores de la entidad.

 

DataSet GetEntityInstance(string entitySource, KeyColumn[] keyColumns, string[] columnList): Toma datos de una instancia de la entidad (valores) de la tabla correspondiente a un ID especificado.

 

Parámetros

Descripción

entitySource

Tabla donde la entidad es implementada.

keyColumns

Arreglo que contiene los nombres de la columna a ser utilizada para filtrar los registros.

columnList

Arreglo que contiene el nombre de las columnas a ser consultadas.

RETURNED DataSet

Un conjunto de datos con valores para la entidad.

 

DataSet GetEntityInstancesTable(string entitySource, string[] keyColumns, string[] outputColumnList, string filterText, bool fillSchema, int topReturnRows)

 

Parámetros

Descripción

entitySource

Tabla donde se localiza la entidad.

keyColumns

Arreglo de columnas utilizadas como llaves.

outputColumnList

Columnas a ser incluida en la lista.

filterText

Filtros para ser aplicados en búsqueda de entidades con la clausula o condición WHERE (donde)

fillSchema

Verdadero si la información del esquema debe ser retornada de la base, falso de lo contrario.

topReturnRows

Número de registros a ser regresados.

RETURNED DataSet

Un conjunto de datos con valores para la entidad

 

Object GetAttributeValue(string entitySource, KeyColumn[] keyColumns, string attributeSource)

 

Parámetros

Descripción

entitySource

Tabla donde se implementa la entidad.

keyColumns

Arreglo de columnas utilizadas como llaves.

attributeSource

Columna de variables a regresar.

RETURNED Object

Los valores de los atributos.

 

bool ExistsEntityInstance(string entitySource, KeyColumn[] keyColumns)

 

Parámetros

Descripción

entitySource

Tabla donde se implementa la entidad.

keyColumns

Arreglo de columnas utilizadas como llaves.

RETURNED bool

Verdadero si la instancia fue encontrada, falso de lo contrario.

 

int ExistsEntityInstance(string entitySource, EntityColumn columnToFind, KeyColumn[] keyColumns)

 

Parámetros

Descripción

entitySource

Tabla donde se implementa la entidad.

columnToFind

Columna utilizada para encontrar la instancia.

keyColumns

Arreglo de columnas utilizadas como llave.

RETURNED int

Debe retornar, “1” si la instancia fue encontrada “0” sino.

 

EntityOutputColumn[] AddEntity(string entitySource, EntityColumn[] addColumns, KeyColumn[] keyColumns, EntityAutoColumn[] autoColumns): Adiciona una nueva instancia (valores).

 

Parámetros

Descripción

entitySource

Tabla donde se implementa la entidad

addColumns

Lista de columnas para incluir valores.

keyColumns

Arreglo de columnas utilizadas como llave.

autoColumns

Arreglo de columnas auto-numeric

RETURNED EntityOutputColumn[]

Debe regresar a HashTable que contiene el nombre de la columna emparejada con el valor incluido.

 

EntityOutputColumn[] UpdateEntity(string entSource, EntityColumn[] updateColumns, KeyColumn[] keyColumns, EntityAutoColumn[] autoColumns): Actualiza la información de una instancia de la entidad (valores) en la base de datos y registra la actualización.

 

Parámetros

Descripción

entSource

Tabla donde se implementa la entidad

updateColumns

Hastable que contiene las columnas a ser actualizadas, con los valores de sus parejas.

keyColumns

Arreglo de columnas utilizadas como llave.

autoColumns

Arreglo de columnas auto-numeric

RETURNED EntityOutputColumn[]

Debe regresar a HashTable que contiene el nombre de la columna y el valor que fue incluido.

 

bool DeleteEntity(string entSource, KeyColumn[] keyColumns): Elimina un registro de la base de datos.

 

Parámetros

Descripción

entSource

Tabla donde se implementa la entidad

keyColumns

Arreglo de columnas utilizadas como llave.

RETURNED bool

Debe regresar verdadero si el registro fue borrado, y Falso de lo contrario.

 

Interfaces de constantes: IDatabaseProperties

Tenga en cuenta que Bizagi construirá la consulta y su sintaxis.

De acuerdo a esta idea, asegúrese de definir todas las constantes apropiadas para las consultas en el motor de la Base de datos específico en estas interfaces.

 

 

Ejemplo

En el ejemplo, vamos a configurar una virtualización personalizada para un motor de base de datos MySQL.

 

Vamos a presentar un ejemplo de las clases de virtualización que implementan las interfaces "ICustomProviderDA", "ICustomQueryDA" y "IEntityVirtualDA".

 

note_pin

Tenga en cuenta que el siguiente código ilustra la implementación del método "GetEntity()" (para servir como una guía), sin embargo otros métodos no son incluidos y podría necesitar otro un mayor desarrollo.

 

 

Crear una librería de replicación

En este ejemplo específico, para poder implementar las clases de replicación que conecten la base de datos MySQL, primero se debe descargar e instalar el componente MySQL Connector/NET para realizar la conexión.

 

Para el ejemplo, las siguientes clases fueron desarrolladas utilizando Microsoft Visual Studio. A través de este proyecto .NET se hace referencia a la librería MySql.Data.dll, la cual debió ser instalado por el componente MySQL Connector/Net ya que es necesario.

 

También es necesario hacer referencia a la librería BizAgi.EntityManager.Interfaces.CustomSource.dll de Bizagi.

 

Estas se encuentran en la carpeta “bin” dentro de la carpeta de la aplicación del proyecto (por defecto en  "C:\Bizagi\Enterprise\Projects\[PROJECT_NAME]\WebApplication\bin\").

 

 

CustomRefs

 

 

Class Interface ICustomProviderDA y ICustomQueryDA

using System;

using System.Data;

using BizAgi.EntityManager.Interfaces.CustomSource;

using MySql.Data.MySqlClient;

using System.Collections.Generic;

using System.Collections;

using System.Text;

 

namespace BizagiMySQL

{

 

   public class CMySQLProvider : ICustomProviderDA, ICustomQueryDA

   {

 

       private Dictionary<string, string> _metadata;

       private MySqlConnection _mySqlconn;

       private bool _disposed;

       //--- The array        used to        store the parameters to        a stored procedure

       private readonly List<CMySqlParameter> _params;

 

       public CMySQLProvider()

       {

           _disposed = false;

           _mySqlconn = null;

           _params = new List<CMySqlParameter>();

       }

     

       #region IProviderVirtualDA2 Members

 

       public void AddParameter(string parameterName, BizagiDataType dataType, int size, byte precision, byte scale, object value, ParameterDirection parameterDirection)

       {

           _params.Add(new CMySqlParameter(parameterName, dataType, size, precision, scale, value, parameterDirection));

       }

 

       public void ClearParameters()

       {

           _params.Clear();

       }

 

       public DataSet RunQuery(string query, string tableName)

       {

           MySqlCommand command = new MySqlCommand();

           MySqlDataAdapter adapter = new MySqlDataAdapter();

           DataSet ds = new DataSet();

           command.Connection = this.GetConnection();

           command.CommandText = ReplaceQueryParameters(query, _params);

           command.CommandType = CommandType.Text;

 

           GetParameters(command);

           adapter.SelectCommand = command;

           adapter.Fill(ds, tableName);

         

           return ds;

       }

 

       public IDatabaseProperties Properties

       {

           get { return CMySqlDatabaseConstants.Instance; }

       }

 

       private void GetParameters(MySqlCommand oCmd)

       {

           //--- Get an enumerator        for        the        parameter array        list

           IEnumerator oEnumerator = _params.GetEnumerator();

 

           //--- Loop through the Parameters in the ArrayList

           while (oEnumerator.MoveNext())

           {

 

               //--- Add the SQLParameter object to the SQLCommand        object

               oCmd.Parameters.Add(ConvertParameterToMySqlParameter((CMySqlParameter)oEnumerator.Current));

           }

       }

 

       private MySqlParameter ConvertParameterToMySqlParameter(CMySqlParameter oP)

       {

           MySqlDbType dbType = oP.DataType;

 

           //--- Instantiate a        SqlParameter object

           MySqlParameter mySqlParameter = new MySqlParameter(oP.ParameterName, dbType, oP.Size);

 

           mySqlParameter.Value = oP.Value;

           mySqlParameter.Direction = (ParameterDirection)oP.Direction;

           mySqlParameter.Precision = oP.Precision;

           mySqlParameter.Scale = oP.Scale;

           mySqlParameter.SourceColumn = oP.SourceColumn;

           mySqlParameter.SourceVersion = oP.UseCurrentSourceColumnValue ? DataRowVersion.Current : DataRowVersion.Original;

 

           return mySqlParameter;

       }

 

       /// <summary>

       /// Replace parameter in the form '?', by parametes in the form ':ParamName'

       /// </summary>

       /// <param name="sQuery"></param>

       /// <returns></returns>

       private static string ReplaceQueryParameters(string sQuery, List<CMySqlParameter> alParams)

       {

           if (alParams != null && alParams.Count > 0)

           {

               char cInter = '?', cQuote = '\'', cAt = '@', cColon = ':';

               string sParamToken = ":";

               bool bInQuote = false; // indicates if current character is in ''

               StringBuilder sbResp = new StringBuilder();

               int _i = 0, _n = sQuery.Length, nNumParam = 0, nLastStrIndex = 0;

               while (_i < _n)

               {

                   if (bInQuote)

                   {

                       if (sQuery[_i] == cQuote)

                       {

                           if ((_i + 1) < _n && sQuery[_i + 1] == cQuote)

                           {

                               // "...''..." case, already in quote

                               _i += 2;

                           }

                           else

                           {

                               // "...'" case

                               bInQuote = false;

                               _i++;

                           }

                       }

                       else

                       {

                           _i++;

                       }

                   }

                   else

                   {

                       if (sQuery[_i] == cInter)

                       {

                           // "...?..." case

                           if (nNumParam >= alParams.Count)

                           {

                               // parameter doesn't exists

                               throw new Exception(string.Format("Parameter {0} doesn't exists in command: '{1}'", nNumParam, sQuery));

                           }

                           else

                           {

                               // get valid param name

                               string sValidParamName = GetValidParamName(((CMySqlParameter)alParams[nNumParam]).ParameterName, alParams, nNumParam - 1);

                               (alParams[nNumParam]).ParameterName = sValidParamName;

 

                               // replace parameter by name

                               sbResp.Append(sQuery.Substring(nLastStrIndex, _i - nLastStrIndex));

                               sbResp.Append(sParamToken + sValidParamName);

 

                               nLastStrIndex = _i + 1;

                               nNumParam++;

                           }

                       }

                       else if (sQuery[_i] == cAt)

                       {

                           // replace parameter by name

                           sbResp.Append(sQuery.Substring(nLastStrIndex, _i - nLastStrIndex));

                           sbResp.Append(cInter);

 

                           nLastStrIndex = _i + 1;

                           nNumParam++;

                       }

                       else if (sQuery[_i] == cQuote)

                       {

                           // "'..." case

                           bInQuote = true;

                       }

                       _i++;

                   }

               }

               sbResp.Append(sQuery.Substring(nLastStrIndex, _n - nLastStrIndex));

               return sbResp.ToString();

           }

           return sQuery;

       }

 

       /// <summary>

       /// Gets a valid parameter name, unique for first iMaxParamIndex parameters

       /// </summary>

       /// <param name="sParamName"></param>

       /// <param name="alParams"></param>

       /// <param name="iMaxParamIndex"></param>

       /// <returns></returns>

       private static string GetValidParamName(string sParamName, List<CMySqlParameter> alParams, int iMaxParamIndex)

       {

           int iMaxDbIdLength = CMySqlDatabaseConstants.Instance.MaxDbIdLength;

           string sResp = (iMaxDbIdLength < sParamName.Length) ? sParamName.Substring(0, iMaxDbIdLength) : sParamName;

           int iSuffix = 1;

           while (IndexOfParam(sResp, alParams, iMaxParamIndex) != -1)

           {

               // find an unique name

               string sSuffix = iSuffix.ToString();

               sResp = (iMaxDbIdLength - sSuffix.Length < sParamName.Length) ? sParamName.Substring(0, iMaxDbIdLength - sSuffix.Length) : sParamName;

               sResp += sSuffix;

               iSuffix++;

           }

           return sResp;

       }

 

       private static int IndexOfParam(string sParamName, List<CMySqlParameter> alParams, int iMaxParamIndex)

       {

           int i = 0, n = iMaxParamIndex;

           while (i < n)

           {

               if ((alParams[i]).ParameterName == sParamName)

               {

                   n = i;

               }

               else

               {

                   i++;

               }

           }

           return (n == iMaxParamIndex) ? -1 : n;

       }

 

       #endregion

 

       #region IProviderVirtualDA Members

 

       public void Init(Dictionary<string, string> metadata)

       {

           this._metadata = metadata;

       }

 

       public void BeginTransaction()

       {

       }

 

       public void Commit()

       {

       }

 

       public void Rollback()

       {

       }

 

       public void OpenConnection()

       {

           if (_mySqlconn == null)

           {

               //Verify all parameters are filled

               if (!_metadata.ContainsKey("Server") || !_metadata.ContainsKey("Database") ||

               !_metadata.ContainsKey("Username") || !_metadata.ContainsKey("Password"))

               {

                   throw new CustomVirtualizationException("Incomplete metadata: connection parameters missing");

               }

               else

               {

                   //Build the connection string with the parameters received from Bizagi Server

                   string sServer = _metadata["Server"];

                   string sDatabase = _metadata["Database"];

                   string sUsername = _metadata["Username"];

                   string sPassword = _metadata["Password"];

                   string sConn = "Server=" + sServer + ";Database=" + sDatabase + ";Uid=" + sUsername + ";Pwd=" + sPassword + ";";

 

                   _mySqlconn = new MySqlConnection(sConn);

                   _mySqlconn.Open();

               }

           }

       }

 

       public void CloseConnection()

       {

           if (_mySqlconn != null)

               _mySqlconn.Close();

           _mySqlconn = null;

       }

 

       #endregion

 

       #region IDisposable Members

 

       void  IDisposable.Dispose()

       {

           if (!_disposed)

           {

               _disposed = true;

           }

       }

 

       #endregion

 

       #region internal methods

 

       internal MySqlConnection GetConnection()

       {

           return this._mySqlconn;

       }

 

       internal DataSet ExecuteMySQLQuery(string sSQL)

       {

           DataSet ds = new DataSet();

 

           MySqlCommand command = new MySqlCommand(sSQL, this.GetConnection());

           MySqlDataAdapter adapter = new MySqlDataAdapter(command);

           adapter.Fill(ds);

 

           return ds;

       }

 

       internal DataSet ExecuteMySQLQuery(MySqlCommand command)

       {

           DataSet ds = new DataSet();

 

           MySqlDataAdapter adapter = new MySqlDataAdapter(command);

           adapter.Fill(ds);

 

           return ds;

       }

 

       internal void ExecuteNonQueryMySQL(string sSQL)

       {

           MySqlCommand command = new MySqlCommand(sSQL, this.GetConnection());

           command.ExecuteNonQuery();

       }

 

       /// <summary>

       /// Initializes command with current connection and transaction

       /// </summary>

       internal MySqlCommand GetCommand()

       {

 

           MySqlCommand m_oledbCmd = new MySqlCommand();

           m_oledbCmd.Connection = GetConnection();

           m_oledbCmd.CommandType = CommandType.Text;

           m_oledbCmd.Parameters.Clear();

 

           return m_oledbCmd;

       }

 

       #endregion

   }

 

}

 

 

 

Clase de la interfaz ICustomVirtualizationDA

using System;

using System.Collections.Generic;

using System.Data;

using System.Collections;

using System.Collections.Specialized;

using System.Text;

using BizAgi.EntityManager.Interfaces.CustomSource;

using MySql.Data.MySqlClient;

 

namespace BizagiMySQL

{

 

   public class CMySQLEntity : ICustomVirtualizationDA

   {

       /// <summary>

       /// Flag to show if object has been disposed                

       /// </summary>

       protected bool m_bDisposed;

 

       /// <summary>

       /// Metadata used to initialize object, as collection of name-value pairs

       /// </summary>

       protected HybridDictionary m_htMetadata;

 

 

       /// <summary>

       /// Connection with the virtual System

       /// </summary>

       protected CMySQLProvider m_objSystem;

 

 

       public CMySQLEntity()

       {

           m_bDisposed = false;

       }

 

       #region ICustomVirtualizationDA Members

 

       public void Init(ICustomProviderDA objProvider)

       {

           m_objSystem = (CMySQLProvider)objProvider;

       }

 

       public EntityOutputColumn[] AddEntity(string entitySource, EntityColumn[] addColumns, KeyColumn[] keyColumns, EntityAutoColumn[] autoColumns)

       {

           List<EntityOutputColumn> htResult = new List<EntityOutputColumn>();

 

           try

           {

               StringBuilder sbIntoList = new StringBuilder(addColumns.Length * 10);

               StringBuilder sbValuesList = new StringBuilder(addColumns.Length * 10);

 

               // Columns to add

               MySqlCommand command = this.m_objSystem.GetCommand();

 

               int pos = 0;

               foreach (EntityColumn oEntry in addColumns)

               {

                   if (pos++ > 0)

                   {

                       sbIntoList.Append(",");

                       sbValuesList.Append(",");

                   }

 

                   // Builds INTO clause and VALUES clauses separately

                   sbIntoList.Append(oEntry.Name);

 

                   // Adds values as parameters

                   sbValuesList.Append("@param"+pos);

                   command.Parameters.AddWithValue("@param"+pos, oEntry.Value);

               }

 

               if (sbIntoList.Length == 0 || sbValuesList.Length == 0)

               {

                   throw new CustomVirtualizationException("Nothing to insert.");

               }

 

               StringBuilder sbSQL = new StringBuilder();

 

               // Inserts values in entity table

               sbSQL.Append("INSERT INTO ");

               sbSQL.Append(entitySource);

               sbSQL.Append(" ( ");

               sbSQL.Append(sbIntoList);

               sbSQL.Append(" ) VALUES ( ");

               sbSQL.Append(sbValuesList);

               sbSQL.Append(" ) ");

 

               command.CommandText = sbSQL.ToString();

               command.ExecuteNonQuery();

 

               //Check if some of the Column is autoFilled... (it should be part of the key, but this is not really neccesary)

               //It can only be ONE autoFilledColumn

               if (autoColumns.Length > 0)

               {

                   command = m_objSystem.GetCommand();

                   command.CommandText = "SELECT last_insert_id()";

                   object ret = command.ExecuteScalar();

 

                   htResult.Add(new EntityOutputColumn { Name = autoColumns[0].Name, DataType = autoColumns[0].DataType, Value = ret });

               }

 

               return htResult.ToArray();

           }

           catch (Exception e)

           {

               throw new ApplicationException(e.Message);

           }

       }

 

       public EntityOutputColumn[] UpdateEntity(string entSource, EntityColumn[] updateColumns, KeyColumn[] keyColumns, EntityAutoColumn[] autoColumns)

       {

           MySqlCommand command = null;

           List<EntityOutputColumn> htResult = new List<EntityOutputColumn>();

 

           try

           {

               StringBuilder sbColsList = new StringBuilder(updateColumns.Length * 10);

 

               command = m_objSystem.GetCommand();

 

               // Loop thru attributes to update, to build SET clause

               int pos = 0;

               foreach (EntityColumn oEntry in updateColumns)

               {

                   if (pos++ > 0)

                   {

                       sbColsList.Append(",");

                   }

 

                   sbColsList.Append(oEntry.Name);

 

                   // Adds values as parameters

                   sbColsList.Append("=@param" + pos);

                   command.Parameters.AddWithValue("@param" + pos, oEntry.Value);

               }

 

               // Builds SQL update query

               if (updateColumns.Length > 0 && sbColsList.Length > 0)

               {

                   StringBuilder sbSQL = new StringBuilder();

 

                   sbSQL.Append(" UPDATE ");

                   sbSQL.Append(entSource);

                   sbSQL.Append(" SET ");

                   sbSQL.Append(sbColsList);

 

                   sbSQL.Append(" WHERE ");

                   sbSQL.Append(BuildWhereClause(command, keyColumns));

 

                   // Performs update!

                   command.CommandText = sbSQL.ToString();

                   command.ExecuteNonQuery();

                   command.Parameters.Clear();

               }

 

               return htResult.ToArray();

           }

           finally

           {

               // Dispose the SqlCommand

               if (command != null)

               {

                   command.Dispose();

               }

           }

       }

 

       public bool DeleteEntity(string entSource, KeyColumn[] keyColumns)

       {

           MySqlCommand command = null;

 

           try

           {

               command = m_objSystem.GetCommand();

 

               StringBuilder sbSQL = new StringBuilder();

 

               // Delete from entity table

               sbSQL.Append("DELETE FROM ");

               sbSQL.Append(entSource);

 

               sbSQL.Append(" WHERE ");

               sbSQL.Append(BuildWhereClause(command, keyColumns));

 

               // Performs delete!

               command.CommandText = sbSQL.ToString();

               return command.ExecuteNonQuery() > 0;

           }

           finally

           {

               // Dispose the SqlCommand

               if (command != null)

               {

                   command.Dispose();

               }

           }

       }

 

       public DataSet GetEntityInstance(string entitySource, KeyColumn[] keyColumns, string[] columnList)

       {

           try

           {

               MySqlCommand command = m_objSystem.GetCommand();

 

               StringBuilder sbSQL = new StringBuilder();

 

               sbSQL.Append(" SELECT ");

               sbSQL.Append(string.Join(",", columnList));

               sbSQL.Append(" FROM ");

               sbSQL.Append(entitySource);

               sbSQL.Append(" WHERE ");

               sbSQL.Append(BuildWhereClause(command, keyColumns));

 

               command.CommandText = sbSQL.ToString();

               DataSet ds = m_objSystem.ExecuteMySQLQuery(command);

 

               return ds;

           }

           catch (Exception e)

           {

               throw new ApplicationException(e.Message);

           }

       }

 

 

       public object GetAttributeValue(string entitySource, KeyColumn[] keyColumns, string attributeSource)

       {

           try

           {

               MySqlCommand command = m_objSystem.GetCommand();

 

               StringBuilder sbSQL = new StringBuilder();

 

               // Column to be retrieved

               sbSQL.Append("SELECT ");

               sbSQL.Append(attributeSource);

 

               // FROM clause

               sbSQL.Append(" FROM ");

               sbSQL.Append(entitySource);

 

               // Uses surrogate key value to find instance

               sbSQL.Append(" WHERE ");

               sbSQL.Append(BuildWhereClause(command, keyColumns));

 

               command.CommandText = sbSQL.ToString();

               DataSet ds = m_objSystem.ExecuteMySQLQuery(command);

               DataTable dtAttribValues = ds.Tables[0];

 

               return dtAttribValues;

           }

           catch (Exception e)

           {

               throw new ApplicationException(e.Message);

           }

       }

 

       public DataSet GetEntityInstancesTable(string sEntSource, string[] arrsKeyColumns, string[] arrsColList, string sFilterText, bool bFillSchema, int iTopReturnRows)

       {

           try

           {

               StringBuilder sbSQL = new StringBuilder();

               sbSQL.Append(" SELECT ");

               sbSQL.Append(string.Join(",", arrsColList));

               // FROM clause

               sbSQL.Append(" FROM ");

               sbSQL.Append(sEntSource);

               // WHERE clause

               if (sFilterText.Length > 0)

               {

                   // Filter text must be formatted in OleDb syntax

                   sbSQL.Append(" WHERE ");

                   sbSQL.Append(sFilterText);

               }

               sbSQL.Append(" ORDER BY ");

               sbSQL.Append(string.Join(",", arrsKeyColumns));

 

               DataSet ds = m_objSystem.ExecuteMySQLQuery(sbSQL.ToString());

               ds.Tables[0].TableName = "ENTITYINSTANCES";

               // Data table with values

               //DataTable dtAttribValues = ds.Tables[0];

             

               /*XmlDataDocument xmlDoc = new XmlDataDocument(ds);

               string sAux = xmlDoc.InnerXml;

               sAux = sAux.Replace("Table", "ENTITYINSTANCES");

               return sAux;*/

               return ds;

           }

           catch (Exception e)

           {

               throw new ApplicationException(e.Message);

           }

       }

 

       public bool ExistsEntityInstance(string entitySource, KeyColumn[] keyColumns)

       {

           try

           {

               MySqlCommand command = m_objSystem.GetCommand();

 

               StringBuilder sbSQL = new StringBuilder();

 

               sbSQL.Append(" SELECT ");

               sbSQL.Append(" count(1) ");

               sbSQL.Append(" FROM ");

               sbSQL.Append(entitySource);

               sbSQL.Append(" WHERE ");

               sbSQL.Append(BuildWhereClause(command, keyColumns));

 

               command.CommandText = sbSQL.ToString();

               object ret = command.ExecuteScalar();

 

               int result;

               if (int.TryParse(ret.ToString(), out result))

                   return result > 0;

               else

                   return false;

           }

           catch (Exception e)

           {

               throw new ApplicationException(e.Message);

           }

       }

 

       public int ExistsEntityInstance(string entitySource, EntityColumn columnToFind, KeyColumn[] keyColumns)

       {

           try

           {

               MySqlCommand command = m_objSystem.GetCommand();

 

               StringBuilder sbSQL = new StringBuilder();

 

               sbSQL.Append(" SELECT ");

               sbSQL.Append(BuildKeySelectClause(keyColumns));

               sbSQL.Append(" FROM ");

               sbSQL.Append(entitySource);

               sbSQL.Append(" WHERE ");

               sbSQL.Append(columnToFind);

               sbSQL.Append(" = ");

               sbSQL.Append("@keyParam");

 

               command.Parameters.AddWithValue("@keyParam", columnToFind.Value);

 

               command.CommandText = sbSQL.ToString();

               object ret = command.ExecuteScalar();

 

               int result;

               if (int.TryParse(ret.ToString(), out result))

                   return result;

               else

                   return 0;

 

           }

           catch (Exception e)

           {

               throw new ApplicationException(e.Message);

           }

       }

 

       #endregion

 

       #region IDisposable Members

 

       public void Dispose()

       {

           if (!m_bDisposed)

           {

               m_bDisposed = true;

           }

       }

 

       #endregion

 

       public string BuildWhereClause(MySqlCommand command, KeyColumn[] keyColumns)

       {

           StringBuilder sbSQL = new StringBuilder();

 

           for (int iKeyIndex = 0; iKeyIndex < keyColumns.Length; iKeyIndex++)

           {

               if (iKeyIndex > 0)

                   sbSQL.Append(" AND ");

 

               // Associate columns with values....

               sbSQL.Append(keyColumns[iKeyIndex].Name);

               sbSQL.Append(" = ");

               sbSQL.Append("@keyParam"+iKeyIndex);

 

               command.Parameters.AddWithValue("@keyParam"+iKeyIndex, keyColumns[iKeyIndex].Value);

           }

 

           return sbSQL.ToString();

       }

 

       public string BuildKeySelectClause(KeyColumn[] keyColumns)

       {

           StringBuilder builder = new StringBuilder();

 

           for (int i = 0; i < keyColumns.Length; i++)

           {

               if (i > 0) builder.Append(", ");

 

               var keyColumn = keyColumns[i];

               builder.Append(keyColumn.Name);

           }

 

           return builder.ToString();

       }

   }

}

 

 

Clase de Parámetros

using BizAgi.EntityManager.Interfaces;

using BizAgi.EntityManager.Interfaces.CustomSource;

using MySql.Data.MySqlClient;

 

namespace BizagiMySQL {

 

 using System.Data;

 

 public class CMySqlParameter

 {

         private BizagiDataType                dataType;                                                //--- Provider-independent data type                        

       private MySqlDbType         dbDataType;                                                //--- Provider-specific datatype of the parameter

     private string                                paramName;                                                //--- The Internal name of the parameter

     private string                                originalParamName;                                //--- The Original o External name of the parameter

 

         //-------------------------------------------------------------------------------------------------------

         //--- Class Constructors

         //--- Overloaded:        Yes

         //-------------------------------------------------------------------------------------------------------

         public CMySqlParameter(string sParameterName, BizagiDataType BizagiDataType, int iSize, object oValue) {

                 ParameterName = sParameterName;

                 dataType = BizagiDataType;

                 dbDataType = getSqlDataType(BizagiDataType);

                 Size = iSize;

                 Value = oValue;

                 Direction = ParameterDirection.Input;

         }

 

         public CMySqlParameter (string sParameterName, BizagiDataType BizagiDataType, int iSize, object oValue, ParameterDirection eDirection) {

                 ParameterName = sParameterName;

                 dataType = BizagiDataType;

                 dbDataType = getSqlDataType(BizagiDataType);

                 Size = iSize;

                 Value = oValue;

                 Direction = eDirection;

         }

 

         public CMySqlParameter (string sParameterName, BizagiDataType BizagiDataType, int iSize, byte iPrecision, byte iScale, object oValue, ParameterDirection eDirection)

         {

                 ParameterName = sParameterName;

                 dataType = BizagiDataType;

                 dbDataType = getSqlDataType(BizagiDataType);

                 Size = iSize;

                 Precision = iPrecision;

                 Scale = iScale;

                 Value = oValue;

                 Direction = eDirection;

         }

 

         public CMySqlParameter (string sParameterName, BizagiDataType BizagiDataType, int iSize, byte iPrecision, byte iScale, object oValue, ParameterDirection eDirection, string sSourceColumn, bool bUseCurrentSourceColumnValue)

         {

                 ParameterName = sParameterName;

                 dataType = BizagiDataType;

                 dbDataType = getSqlDataType(BizagiDataType);

                 Size = iSize;

                 Precision = iPrecision;

                 Scale = iScale;

                 Value = oValue;

                 Direction = eDirection;

                 SourceColumn = sSourceColumn;

                 UseCurrentSourceColumnValue = bUseCurrentSourceColumnValue;

         }

 

       public ParameterDirection Direction { get; private set; }

 

       public object Value { get; private set; }

 

       public string SourceColumn { get; private set; }

 

       public string ParameterName

         {

           get { return paramName; }

             set

                 {

                         string sResult = value;

                         originalParamName = value;

 

                         paramName = sResult.Replace ("@","?");

                 }

         }

 

         //--

         // Only for this IParameter implementation

         // ReadOnly -- Return the original name of the parameter

         //--

         public string OriginalName

         {

           get { return originalParamName; }

         }

 

         public BizagiDataType Type

         {

           get { return dataType; }

           set

           {

               dataType = value;

               dbDataType = getSqlDataType(dataType);

           }

         }

 

     public int Size { get; set; }

 

     public byte Precision { get; set; }

 

     public byte Scale { get; set; }

 

     public bool UseCurrentSourceColumnValue { get; set; }

 

     public MySqlDbType DataType

         {

           get { return dbDataType; }

         }

 

         private static MySqlDbType getSqlDataType(BizagiDataType BizagiDataType) {

           MySqlDbType oDbType = MySqlDbType.Int32;

 

                 switch (BizagiDataType) {

 

                         case BizagiDataType.BigInt:

                   oDbType = MySqlDbType.Int64;

                                 break;

 

                         case BizagiDataType.Int:

                   oDbType = MySqlDbType.Int32;

                                 break;

 

                         case BizagiDataType.SmallInt:

                   oDbType = MySqlDbType.Int16;

                                 break;

 

                         case BizagiDataType.TinyInt:

                   oDbType = MySqlDbType.Byte;

                                 break;

 

                         case BizagiDataType.Boolean:

                   oDbType = MySqlDbType.Bit;

                                 break;

 

                         case BizagiDataType.Decimal:

                   oDbType = MySqlDbType.Decimal;

                                 break;

 

                         case BizagiDataType.Numeric:

                   oDbType = MySqlDbType.Float;

                                 break;

 

                         case BizagiDataType.Money:

                   oDbType = MySqlDbType.Decimal;

                                 break;

 

                         case BizagiDataType.Float:

                   oDbType = MySqlDbType.Float;

                                 break;

 

                         case BizagiDataType.Real:

                   oDbType = MySqlDbType.Float;

                                 break;

 

                         case BizagiDataType.DateTime:

                   oDbType = MySqlDbType.DateTime;

                                 break;

 

                         case BizagiDataType.SmallDateTime:

                   oDbType = MySqlDbType.DateTime;

                                 break;

 

                         case BizagiDataType.Char:

                   oDbType = MySqlDbType.VarChar;

                                 break;

 

                         case BizagiDataType.VarChar:

                   oDbType = MySqlDbType.VarChar;

                                 break;

                 

                         case BizagiDataType.Text:

                   oDbType = MySqlDbType.Text;

                                 break;

                 

                         case BizagiDataType.Binary:

                   oDbType = MySqlDbType.Binary;

                                 break;

 

                         case BizagiDataType.VarBinary:

                   oDbType = MySqlDbType.VarBinary;

                                 break;

 

                         case BizagiDataType.Image:

                   oDbType = MySqlDbType.VarBinary;

                                 break;

 

                         case BizagiDataType.Guid:

                   oDbType = MySqlDbType.Guid;

                                 break;

 

               case BizagiDataType.NChar:

                   oDbType = MySqlDbType.VarChar;

                   break;

 

               case BizagiDataType.NVarChar:

                   oDbType = MySqlDbType.VarChar;

                   break;

 

               case BizagiDataType.NText:

                   oDbType = MySqlDbType.Text;

                   break;

 

                         default:

                                 break;

                 }

 

                 return oDbType;

 

         }

 }

}

 

 

Clase de la Interfaz IDatabaseProperties

using BizAgi.EntityManager.Interfaces.CustomSource;

 

namespace BizagiMySQL

{

   /// <summary>

   /// Specific database constants

   /// </summary>

   public class CMySqlDatabaseConstants : IDatabaseProperties

   {

       #region Singleton

 

       private static readonly CMySqlDatabaseConstants MySqlInstance = new CMySqlDatabaseConstants();

 

       public static CMySqlDatabaseConstants Instance

       {

           get { return MySqlInstance; }

       }

 

       protected CMySqlDatabaseConstants() {}

 

       #endregion

 

       #region Fields / Properties

 

       /// <summary>

       /// Open character for enclose a name that is reserverd word or has special characters

       /// </summary>

       private readonly string m_sQuotedNameOpenChar = "'";

       public string QuotedNameOpenChar { get { return m_sQuotedNameOpenChar; } }

 

       /// <summary>

       /// Close character for enclose a name that is reserverd word or has special characters

       /// </summary>

       private readonly string m_sQuotedNameCloseChar = "'";

       public string QuotedNameCloseChar { get { return m_sQuotedNameCloseChar; } }

 

       /// <summary>

       /// Indicates if by default comparisons between strings are case sensitive

       /// </summary>

       private readonly bool m_bCaseSensitive = false;

       public bool CaseSensitive { get { return m_bCaseSensitive; } }

 

       internal int MaxDbIdLength

       {

           get { return 128; }

       }

 

       #endregion

   }

}

 

Una vez haya terminado la implementación de las clases, debe construir el componente como una librería (para este ejemplo una librería dll).

 

 

Configurar el proveedor en Bizagi

En este paso, vamos a configurar el Sistema y el proveedor de datos de la virtualización especificando que librería debe ser usada (el componente personalizado creado anteriormente).

 

note_pin

Tenga en cuenta que la configuración es hecha a través del método de configuración estándar de virtualización, el cual requiere que las entidades a ser virtualizadas hayan sido creadas en el modelo de datos de Bizagi.

 

1. Clic en Sistemas, en la vista de Experto de Bizagi.

Puede dar clic derecho sobre el elemento sistema y seleccionar Nuevo Sistema del menú desplegable o dar clic en Nuevo sistema de la barra del menú.

 

 

VR_Both02_NewSystem

 

2. Ingrese el Nombre, Nombre Visual y Descripción para el nuevo sistema y seleccione el checkbox de Permitir Entidades Virtuales para replicación para este sistema.

Clic en Ok para guardar cambios.

 

CustomVirtualization_Image002

 

3. Clic en el signo (+) al lado del sistema recién creado.

Clic derecho en el elemento Nuevo Proveedor.

 

CustomVirtualization_Image003

 

4. En la ventana del Nuevo Proveedor ingrese Nombre, Nombre Visual y Descripción en la pestaña de Cconfiguración Básica.

Marque la opción Permitir Entidades Virtuales para este proveedor. También marque la opción Permitir Replicación para este proveedor (si aplica).

 

CustomVirtualization_Image004

 

5. Seleccione la pestaña de Detalles de Conexión y dé clic en Nueva librería.

 

CustomVirtualization_Image005

 

 

6. Ingrese Nombre, Nombre Visual y Descripción.

Luego haga clic en Seleccionar Librería para seleccionar el .dll de la librería de virtualización personalizada creada previamente.

Dé clic en Ok en la ventana de Nueva Librería.

 

 

CustomVirtualization_Image006

 

 

7. Dé clic en el botón Nueva Clase y dentro de la ventana Nueva Clase para Librería, ingrese el nombre de la clase que implementa la interfaz IProviderVirtualDA.

Dé clic en Ok .

 

CustomVirtualization_Image007

 

8. Ahora, en la pestaña Conexión Desarrollo, incluya las propiedades de la conexión haciendo clic en el botón Metadata para crear una nueva fila Propiedad-Valor.

Dé clic en Ok.

 

CustomVirtualization_Image008

 

9.Expanda el elemento nuevo proveedor, seleccione el elemento Entidades Virtuales y cree una Nueva Clase de Virtualización.

 

CustomVirtualization_Image009

 

10. Seleccione la librería de la lista desplegable en la ventana Nueva Clase para Librería (si la clase de la Entidad esta en la misma librería que la Clase del Proveedor) o incluya una nueva dando clic en Nueva Librería..

 

CustomVirtualization_Image010

 

Dé clic en Nueva Clase y complete los campos necesarios en la nueva ventana.

Haga clic en Ok para completar la Configuración de la Clase de la Entidad.

 

 

CustomReplication_Image002

 

 

11.Dé clic derecho sobre el nuevo elemento de la clase de la entidad y seleccione la opción Adicionar Entidad a Virtualización.

 

CustomVirtualization_Image012

 

12. En la ventana Adicionar Entidad, seleccione una entidad maestra de la lista desplegable. Luego, en el campo de fuente externa, ingrese el nombre de la tabla o vista de la fuente.

Después seleccione uno (o más de un) atributo de la lista de atributos de la entidad de Bizagi, para que sean la llave de negocio (un atributo que tendrá un único valor, el cual puede ser utilizad para diferenciar un registro de otro).

 

Dé clic en OK para guardar los cambios.

 

CustomVirtualization_Image013

 

13. Seleccione la entidad virtualizada y para cada atributo seleccione el atributo externo correspondiente. Esto se realiza dando clic derecho sobre el atributo y seleccionando la opción Propiedades.

 

CustomVirtualization_Image014

 

 

En la ventana Editar Atributo, escriba el nombre del atributo externo y haga clic en OK.

 

CustomVirtualization_Image015

 

 

note_pin

Si su librería de Virtualización personalizada tiene referencias a otras librerías, es necesario copiarlas a una carpeta de Bizagi Studio, (por defecto en "C:\Program Files\Bizagi\Bizagi Standard\Studio"), y en la carpeta bin de la carpeta aplicación web (por defecto en "C:\Bizagi\Standard\Projects\[PROJECT_NAME]\WebApplication\bin").

Esto último se hace para que la virtualización funciona en tiempo de ejecución.

 

Ya hemos terminado la configuración de la Virtualización utilizando un componente personalizado para una base de datos MySQL.

 

 

Verificar Virtualización (Punto de chequeo)

Una vez la Virtualización ha sido configurada, usted puede verificar si se ha sincronizado de forma apropiada las entidades maestras con las tablas externas. 

 

Tenga en cuenta que con la Virtualización, los procesos en Bizagi acceden a información almacenada en diferentes fuentes de datos en tiempo de ejecución. 

 

Esta funcionalidad es transparente para los usuarios del Portal de Trabajo; por lo que usted necesita verificar que la virtualización funcione de forma adecuada. Esto se realiza verificando en la forma de la actividad donde se utiliza la información de las entidades virtualizadas. 

Adicionalmente, verifique de forma explicita los valores que se están sincronizando con la fuente. Usted puede ver los valores en la entidad especifica a través del modulo entidades (disponible para el ambiente de desarrollo)  como se indica en Verificar la Virtualización.