HOWTO: Consultar el registro de base de datos mediante X++

Una característica muy interesante de Microsoft Dynamics AX es su capacidad para realizar auditoría de cualquier tabla que necesitemos de manera estándar y configurable mediante la funcionalidad “Registro de base de datos“.

Este registro es muy sencillo de configurar, se eligen las tablas y los campos que se desean auditar. Por ejemplo, en este caso queremos guardar un registro de las modificaciones en la tabla de proyectos:

SysDataBaseLog | 1

y se configuran los eventos que se desea almacenar de estas tablas. En el ejemplo vamos a auditar todos los eventos: Insertar, Actualizar, Eliminar y cambiar la clave primaria (renombrar):

SysDataBaseLog | 2

Ya tenemos configurado el registro. A partir de ahora cualquier modificación quedará registrada con el valor anterior, el valor nuevo, el usuario y la fecha/hora de la modificación. Como un gran hermano 🙂

SysDataBaseLog | 3

Para hacer una prueba, cambio el nombre a un proyecto para que se genere un registro de auditoría:

SysDataBaseLog | 4

Esto está genial y funciona muy bien de manera estándar, pero es posible que queramos acceder a estos datos mediante código, para hacer nuestras propias consultas a la tabla SysDataBaseLog, donde se guardan estos datos.

El problema es que (aparte de ciertas limitaciones de permisos, que podemos configurar), los datos no se guardan en un formato demasiado “accesible”, como muestro en la siguiente imagen :

SysDataBaseLog | 5

Los datos de la modificación en sí (los valores antiguo y nuevo de cada campo) se guardan en un contenedor codificados y no es muy intuitiva la manera de descodificarlos.

Dejo aquí un ejemplo con el código X++ necesario para conseguirlo. Parto de una tabla (_tableId), un campo (_fieldId) y un un RecId y nos va a devolver mediante el InfoLog todos los cambios que se hayan registrado sobre ese campo:

static void JAEE_ConsultaAuditoria(Args _args)
{
    #define.FieldIdIdx(1)
    #define.FieldIdMask(0xFFFF)
    #define.NewValIdx(2)
    #define.OldValIdx(3)

    // Campo de la tabla que queremos auditar
    TableId         _tableId    = tableNum(ProjTable);
    FieldId         _fieldId    = fieldNum(ProjTable, Name);
   
    // Registro de la tabla que queremos auditar
    RecId           _recId      = 5637144586;

    SysDataBaseLog  dbLog;
    FieldId         fieldId;
    container       logRec;
    str             newVal, oldVal;
    List            list;
    ListIterator    lit;
    int             i;
    ;

    // Tabla estándar de auditoría, busco la tabla que me interesa
    while select dbLog
        where dbLog.table       == _tableId &&
              dbLog.LogRecId    == _recId
    {
        // Obtengo un iterador de todos los cambios guardados en el contenedor
        list = dbLog.getDataAslist();
        lit  = new ListIterator(list);
        while (lit.more())
        {
            logRec  = lit.value();
           
            // Obtener el ID del campo
            fieldId = conpeek(logRec, #FieldIdIdx);
            fieldId = fieldId & #FieldIdMask;

            // Si es el campo que estamos buscando, muestro el resultado
            if (_fieldId == fieldId)
            {
                // Valor anterior, y nuevo
                newVal = conpeek(logRec, #NewValIdx);
                oldVal = conpeek(logRec, #OldValIdx);

                info(strfmt("Modificado por %1 el %2. Antes: %3, Ahora: %4",
                             dbLog.createdBy, dbLog.createdDateTime, oldVal, newVal));
            }

            lit.next();
        }
    }
}

Descarga