Comprender el atributo PXProjection de Acumatica

El atributo PXProjection se utiliza para definir una nueva clase DAC derivada de la interfaz IBqlTable o de cualquier otro DAC existente, con columnas/campos/propiedades específicas procedentes de DAC incluidos en una sentencia select que define los datos gestionados por esta nueva clase.
Dioris Aguilar | 26 de julio de 2022

Comprender el atributo PXProjection de Acumatica

Introducción

Desde cierto punto de vista, un ERP es básicamente un sistema para almacenar y manipular datos introducidos por los usuarios. Es sin duda un punto de vista muy general que pone de relieve la importancia de la gestión de los datos dentro del sistema.

En Acumatica, los datos almacenados en la base de datos se manejan a través de una capa que permite a los desarrolladores manipular los datos sin consultar directamente la base de datos. Para los desarrolladores de Acumatica, se trata de una capa de abstracción bien conocida: Business Query Language o simplemente BQL. Esta capa proporciona múltiples formas de manipular datos y una de ellas es el atributo PXProjection.

En este post nos sumergiremos un poco en este atributo, repasaremos algunas de sus propiedades, cómo se puede utilizar y mostraremos escenarios comunes donde se aplica.

Atributo PXProjection

Este atributo se utiliza para definir una nueva clase DAC derivada de la interfaz IBqlTable o de cualquier otro DAC existente, con columnas/campos/propiedades específicas procedentes de DAC's incluidos en una sentencia select que define los datos gestionados por esta nueva clase. Desde cierto punto de vista, podemos ver esta nueva clase DAC como el equivalente de una vista SQL donde ambas definen un conjunto de datos de una sentencia y ambas son una tabla virtual, es decir, no existe una tabla real en la base de datos con sus nombres.

A continuación se muestra un ejemplo de este DAC de proyección utilizando INTranSplit como DAC principal en la sentencia select:

GIST: https://gist.github.com/Dioris/26e2bf16c5634fa550d6bd11482fd7fa

El DAC de proyección anterior selecciona los últimos documentos de entrada liberados para artículos serializados en el sistema y podemos utilizarlo en una declaración de vista para mostrar los registros resultantes en la interfaz de usuario de una pantalla como la que se muestra a continuación:

GIST: https://gist.github.com/Dioris/2ef5dde25d6e9c361637834a8b60284c

o podemos utilizarlo directamente en otra sentencia BQL:

GIST: https://gist.github.com/Dioris/2149a44aab505a6c63c541423d6d85ba

Sin duda, el ejemplo anterior es un poco complejo, pero muestra lo útil que puede ser un DAC de proyección cuando se trata de conjuntos de datos complicados, permitiendo reducir la complejidad del BQL final y haciendo posibles consultas difíciles.

Empecemos por el principio:

Existen básicamente dos formas de declarar un DAC de proyección cuando se trata del objeto base. Podemos definirlo utilizando la interfaz IBqlTable como el ejemplo anterior, o podemos derivar la nueva clase de un DAC existente:

GIST: https://gist.github.com/Dioris/b3f322e3db560f8be6fac8caf7a62c36

En este caso, ambas declaraciones obtendrán todos los pedidos de cliente aprobados. Sin embargo, la principal diferencia entre estas dos definiciones es que la primera requiere que declare las propiedades y campos necesarios, incluyendo al menos los campos clave. En la segunda definición, la nueva proyección DAC hereda todos los campos y propiedades de la clase base(SOOrder).

Como cualquier otro DAC, debemos definir los campos clave para establecer las condiciones de unicidad de sus registros asignando la propiedad IsKey = true al atributo base. Usando el mismo ejemplo anterior, debemos declarar los campos OrderType y OrderNbr para la primera declaración:

GIST: https://gist.github.com/Dioris/37ecc07072c32f73aa1f4a0d29a6cb71

Observe que las propiedades añadidas se mapean explícitamente a una propiedad existente del DAC de la sentencia select asignando el tipo apropiado a la propiedad BqlField. Sin embargo, esto no es necesario cuando se deriva de un DAC existente y este DAC es el mismo que el utilizado en la sentencia select como la segunda definición.

En caso de que necesitemos cambiar alguna propiedad derivada de la clase base, debemos anularla de la siguiente manera:

GIST: https://gist.github.com/Dioris/dfdb49060df1f07a80e493864d0d91a4

Observe que la clase abstracta orderNbr se define con el modificador new para ocultar la definición de la clase base. Esta nueva clase abstracta se utiliza normalmente si esta propiedad se utiliza en otra sentencia Bql. La propiedad OrderNbr debe tener el modificador override para poder establecer los nuevos atributos.

Como se mencionó inicialmente, la sentencia Select puede tener más de una tabla involucrada, lo que significa que tendríamos que mapear los campos necesarios de los DAC's adicionales en caso de que se requiera algún campo de ellos, de lo contrario los DAC's adicionales sólo se utilizarán para filtrar los datos que deseamos.

A continuación se muestra un ejemplo de un DAC de proyección para obtener registros de pedidos de venta con un comportamiento diferente a RM:

GIST: https://gist.github.com/Dioris/d61f6b13ef068e3dd997d7be79a122e0

En este caso, el DAC adicional(SOOrderType) se utiliza únicamente con fines de filtrado, ya que el nuevo DAC de proyección no asigna ningún campo de este DAC adicional(SOOrderType). Sin embargo, podríamos tener una necesidad especial de mapear un campo de esta tabla. Si este es el caso, deberíamos hacerlo de la siguiente manera:

GIST: https://gist.github.com/Dioris/a0620755584c73fb8e00ac96aea97bfd

Propiedad persistente

Por defecto, el DAC de proyección es de sólo lectura, es decir, no permite persistir cambios en la base de datos. Sin embargo, existe una propiedad Persistent que lo permite estableciéndola como true como puedes ver aquí:

GIST: https://gist.github.com/Dioris/403d482003d6b1f4979965ca0f1ea49f

Esta propiedad le permite persistir los cambios en la base de datos, ya sean Insertados, Borrados o en estado Actualizado.

Por supuesto, los cambios pueden persistir en todas las tablas/DAC implicados en la sentencia select. Si los cambios en la tabla principal son persistentes y si varias tablas necesitan ser actualizadas en el DAC de proyección, la documentación dice que los campos que implementan la relación entre la tabla principal y las tablas unidas deben tener el atributo PXExtraKey para permitir la actualización apropiada llamada por la proyección. Puede verlo claramente a continuación:

GIST: https://gist.github.com/Dioris/78c378c17ab91824bd0f38a6b0e986fc

En este caso, la propiedad OrderType es la única implicada en la relación entre las dos tablas y es donde debe colocarse el atributo.

Este atributo también tiene una opción para establecer una lista de las tablas que requieren persistir. En este caso, se pueden excluir las tablas que no lo necesiten:

GIST: https://gist.github.com/Dioris/9f41d1f189a129a3f789987a812298d9

Cuando se utiliza la propiedadpersistente (sin mayúsculas) para establecer la lista de DAC a persistir, la propiedad Persistent se establece en true automáticamente.

¡¡Importante!!

Cuando se actualizan cambios en la base de datos, no se actualizan todos los campos de todos los DAC implicados en la sentencia select: sólo los campos mapeados son los que se actualizarán.

Espero que esta información te ayude a entender mejor este atributo y a mejorar tus consultas BQL.

¡Feliz codificación!

Autor del blog

Dioris entró en el mundo de las TI como ingeniero electrónico en 2005 y encontró la carrera de programación muy desafiante y atractiva. Formó parte del equipo que creó el módulo Field Service, posteriormente adquirido por Acumatica, y ahora diseña y ofrece soluciones personalizadas e integraciones bajo demanda. Ha pasado algún tiempo en su carrera proporcionando soporte técnico a personas sin conocimientos de tecnología, lo que le ha ayudado a diseñar soluciones centradas en el cliente y centradas en proporcionar una experiencia de usuario sin problemas en el producto final. Como antiguo empleado de Acumatica, conoce el poder que se esconde tras el marco de trabajo y disfruta manteniéndose involucrado en el ecosistema.

Reciba las actualizaciones del blog en su bandeja de entrada.