Miklix

Uso del marco SysExtension para determinar qué subclase crear en Dynamics AX 2012

Publicado: 16 de febrero de 2025, 0:25:38 UTC
Última actualización: 12 de enero de 2026, 8:42:57 UTC

Este artículo describe cómo utilizar el marco SysExtension poco conocido en Dynamics AX 2012 y Dynamics 365 for Operations para crear instancias de subclases basadas en decoraciones de atributos, lo que permite un diseño fácilmente extensible de una jerarquía de clases de procesamiento.


Esta página ha sido traducida automáticamente del inglés para hacerla accesible al mayor número de personas posible. Lamentablemente, la traducción automática no es todavía una tecnología perfeccionada, por lo que pueden producirse errores. Si lo prefiere, puede consultar la versión original en inglés aquí:

Using the SysExtension Framework to Find Out Which Subclass to Instantiate in Dynamics AX 2012

La información de esta publicación se basa en Dynamics AX 2012 R3. Puede que no sea válida para otras versiones. (Actualización: Confirmo que la información de este artículo también es válida para Dynamics 365 for Operations).

Al implementar clases de procesamiento en Dynamics AX, a menudo es necesario crear una jerarquía de clases donde cada subclase corresponde a un valor de enumeración o tiene algún otro acoplamiento de datos. Un diseño clásico consiste en tener un método de construcción en la superclase, que cuenta con un modificador que determina qué clase instanciar según la entrada.

Esto funciona bien en principio, pero si tiene muchas entradas posibles diferentes (muchos elementos en una enumeración o quizás la entrada es una combinación de varios valores diferentes), puede volverse tedioso y propenso a errores de mantenimiento y el diseño siempre tiene la desventaja de que necesitará modificar dicho método de construcción si alguna vez agrega una nueva subclase o realiza cambios en qué subclase debe usarse en función de qué entrada.

Afortunadamente, existe una forma mucho más elegante, aunque lamentablemente también mucho menos conocida, de hacer esto: mediante el uso del marco SysExtension.

Este framework aprovecha los atributos que puedes usar para decorar tus subclases y permitir que el sistema determine qué subclase debe usarse para cada función. Aun así, necesitarás un método de construcción, pero si se hace correctamente, nunca tendrás que modificarlo al agregar nuevas subclases.

Veamos un ejemplo imaginario: supongamos que va a implementar una jerarquía que realiza algún tipo de procesamiento basado en la tabla InventTrans. El procesamiento a realizar depende del StatusReceipt y del StatusIssue de los registros, así como de si estos están relacionados con SalesLine, PurchLine o ninguno. Ya está considerando muchas combinaciones diferentes.

Digamos entonces que sabes que por ahora solo necesitas manejar un puñado de combinaciones, pero también sabes que con el tiempo se te pedirá que puedas manejar más y más combinaciones.

Mantengámoslo relativamente simple y digamos que por ahora solo necesita manejar registros relacionados con SalesLine con un StatusIssue de ReservPhysical o ReservOrdered, todas las demás combinaciones se pueden ignorar por ahora, pero como sabe que tendrá que manejarlas más adelante, querrá diseñar su código de una manera que lo haga fácilmente extensible.

Por ahora, su jerarquía podría verse así:

  • MiProcesadorMiProcesador_VentasMiProcesador_Ventas_ReservaOrdenadaMiProcesador_Ventas_ReservaFísica

Ahora, podría implementar fácilmente un método en la superclase que instancia una subclase basándose en una enumeración ModuleInventPurchSales y StatusIssue. Sin embargo, deberá modificar la superclase cada vez que agregue una subclase, y ese no es realmente el concepto de herencia en la programación orientada a objetos. Después de todo, no necesita modificar RunBaseBatch ni SysOperationServiceBase cada vez que agrega un nuevo trabajo por lotes.

En su lugar, puede usar el framework SysExtension. Para ello, deberá agregar otra clase que extienda SysAttribute. Esta clase se usará como el atributo con el que podrá decorar sus clases de procesamiento.

Esta clase es muy similar a cómo crearías una clase de contrato de datos para una implementación de SysOperation, ya que tendrá algunos miembros de datos y métodos parm para obtener y configurar esos valores.

En nuestro caso, la ClassDeclaration podría verse así:

class MyProcessorSystemAttribute extends SysAttribute
{
    ModuleInventPurchSales  module;
    StatusIssue             statusIssue;
    StatusReceipt           statusReceipt
}

Necesita crear un método new() para instanciar todos los miembros de datos. Si lo desea, puede asignar valores predeterminados a algunos o a todos, pero no lo he hecho.

public void new(ModuleInventPurchSales  _module,
                StatusIssue             _statusIssue,
                StatusReceipt           _statusReceipt)
{
    ;

    super();

    module          = _module;
    statusIssue     = _statusIssue;
    statusReceipt   = _statusReceipt;
}

Y también deberías implementar un método parm para cada miembro de datos, pero los he omitido aquí porque estoy seguro de que sabes cómo hacerlo; de lo contrario, considerémoslo un ejercicio ;-)

Ahora puedes usar tu clase de atributo para decorar cada una de tus clases de procesamiento. Por ejemplo, las declaraciones de clase podrían verse así:

[MyProcessorSystemAttribute(ModuleInventPurchSales::Sales,
                            StatusIssue::None,
                            StatusReceipt::None)]
class MyProcessor_Sales extends MyProcessor
{
}

[MyProcessorSystemAttribute(ModuleInventPurchSales::Sales,
                            StatusIssue::ReservOrdered,
                            StatusReceipt::None)]
class MyProcessor_Sales_ReservOrdered extends MyProcessor_Sales
{
}

[MyProcessorSystemAttribute(ModuleInventPurchSales::Sales,
                            StatusIssue::ReservPhysical,
                            StatusReceipt::None)]
class MyProcessor_Sales_ReservPhysical extends MyProcessor_Sales
{
}

Por supuesto, puede nombrar sus clases como desee. Lo importante es que las decore con atributos que correspondan al tipo de procesamiento que realizan. (Pero tenga en cuenta que existen convenciones de nomenclatura para las jerarquías de clases en Dynamics AX y siempre es recomendable seguirlas, si es posible).

Ahora que ha decorado sus clases para identificar qué tipo de procesamiento realiza cada una de ellas, puede aprovechar el marco SysExtension para crear instancias de objetos de las subclases según sea necesario.

En su superclase (MyProcessor), podría agregar un método de construcción como este:

public static MyProcessor construct(ModuleInventPurchSales _module,
StatusIssue _statusIssue,
StatusReceipt _statusReceipt)
{
    MyProcessor                 ret;
    MyProcessorSystemAttribute  attribute;
    ;

    attribute = new MyProcessorSystemAttribute( _module,
                                                _statusIssue,
                                                _statusReceipt);

    ret = SysExtensionAppClassFactory::getClassFromSysAttribute(classStr(MyProcessor), attribute);

    if (!ret)
    {
        //  no class found
        //  here you could throw an error, instantiate a default
        //  processor instead, or just do nothing, up to you
    }

    return ret;
}

La parte realmente interesante, y en realidad el objetivo (perdón por el juego de palabras) de toda esta publicación, es el método getClassFromSysAttribute() de la clase SysExtensionAppClassFactory. Este método acepta el nombre de la superclase de una jerarquía (no es necesario que esta superclase esté en la cima de la jerarquía; simplemente significa que solo las clases que la extienden serán elegibles) y un objeto de atributo.

Luego, devuelve un objeto de una clase que extiende la superclase especificada y está decorado con un atributo correspondiente.

Obviamente, puedes añadir tanta validación o lógica al método de construcción como desees, pero lo importante es que, una vez implementado, no deberías tener que volver a modificarlo. Puedes añadir subclases a la jerarquía y, siempre que las decores correctamente, el método de construcción las encontrará aunque no existieran al momento de su creación.

¿Qué hay del rendimiento? Sinceramente, no he intentado compararlo, pero intuyo que probablemente tenga un rendimiento inferior al del diseño clásico de sentencia switch. Sin embargo, considerando que la mayoría de los problemas de rendimiento en Dynamics AX se deben al acceso a la base de datos, no me preocuparía demasiado.

Claro que, si estás implementando algo que requiere la creación rápida de miles de objetos, quizás quieras investigar más, pero en los casos típicos en los que solo se instancia un objeto para realizar un procesamiento largo, dudo que importe. Además, considerando mi consejo para la resolución de problemas (siguiente párrafo), parece que el framework SysExtension depende del almacenamiento en caché, por lo que, en un sistema en ejecución, dudo que tenga una repercusión significativa en el rendimiento.

Solución de problemas: Si el método de construcción no encuentra las subclases, aunque esté seguro de que están correctamente decoradas, podría tratarse de un problema de caché. Intente borrar las cachés tanto del cliente como del servidor. No debería ser necesario reiniciar el AOS, pero podría ser el último recurso.

Lectura adicional

Si te ha gustado esta publicación, puede que también te gusten estas sugerencias:


Compartir en BlueskyCompartir en FacebookCompartir en LinkedInCompartir en TumblrCompartir en XCompartir en LinkedInPin en Pinterest

Mikkel Christensen

Sobre el autor

Mikkel Christensen
Mikkel es el creador y propietario de miklix.com. Tiene más de 20 años de experiencia como programador informático profesional y desarrollador de software, y actualmente trabaja a tiempo completo para una gran empresa europea de TI. Cuando no está escribiendo en su blog, dedica su tiempo libre a una gran variedad de intereses, aficiones y actividades, que en cierta medida pueden verse reflejados en la variedad de temas tratados en este sitio web.