Aplicaciones Genexus

502
Desarrollo de Aplicaciones Basadas en Tecnologías Genexus

Transcript of Aplicaciones Genexus

Page 1: Aplicaciones Genexus

Desarrollo de

Aplicaciones Basadas

en Tecnologías

Genexus

Page 2: Aplicaciones Genexus
Page 3: Aplicaciones Genexus

1

Introducción Teórica

Page 4: Aplicaciones Genexus

2

Herramientas y Metodologías

Nuestra tarea como profesionales de la informática consiste en desarrollar y mantener aplicaciones para apoyar al usuario en su actividad. Para realizar esta tarea existen diferentes herramientas y metodologías.

GeneXus es una herramienta para el desarrollo de aplicaciones sobre bases de datos. Su objetivo es permitir la implantación de aplicaciones en el menor tiempo y con la mejor calidad posible.

A grandes rasgos, el desarrollo de una aplicación implica tareas de análisis, diseño e implementación. La vía de GeneXus para alcanzar el objetivo anterior es liberar a las personas de las tareas automatizables (como el diseño de la base de datos), permitiéndoles así concentrarse en las tareas realmente difíciles y no automatizables (como comprender los problemas del usuario).

GeneXus emplea una metodología que tiene un enfoque muy diferente al de las metodologías más comúnmente utilizadas. Por tanto, aprender a utilizar GeneXus adecuadamente va más allá de conocer un nuevo lenguaje: lo más importante es aprender su metodología.

Page 5: Aplicaciones Genexus

3

VISIONESDE

USUARIOS

SatisfaceMODELO DE LA

REALIDAD

Ingeniería Inversa

Modelado de la realidadA partir de las visiones de los usuarios

BASEDE

DATOSPROGRAMAS

El primer problema al que nos enfrentamos en el desarrollo de aplicaciones es la obtención del conocimiento de la realidad.

Nadie dentro de la empresa conoce los requerimientos y el alcance de la aplicación a desarrollar como un todo. Entonces, ¿cómo logramos obtener el conocimiento de la realidad de una forma lo suficientemente objetiva y detallada al mismo tiempo, que nos permita construir un modelo corporativo?

Este conocimiento se encuentra en cada una de las visiones de los usuarios. Cada usuario conoce bien los objetos con los que trabaja cotidianamente, la información que se maneja en ellos, las reglas que deben seguirse, los cálculos que deben realizarse.

Por lo tanto, el punto de partida de la metodología GeneXus es: describir las visiones de los usuarios para modelar el sistema; y a partir del modelo de la realidad definido, GeneXus construye el soporte computacional -base de datos y programas- en forma totalmente automática.

Page 6: Aplicaciones Genexus

4

Desarrollo con GeneXus

REALIDAD

DESCRIPCIÓNDE OBJETOS

Utilizando GeneXus, la tarea básica del analista es la descripción de la realidad. Sólo el ser humano puede desarrollar esta tarea ya que sólo él puede entender el problema del usuario.

El analista GeneXus trabaja en alto nivel, en vez de realizar tareas de bajo nivel como: diseñar archivos, normalizar, diseñar programas, programar, buscar y eliminar los errores de los programas.

Para comenzar el desarrollo de una aplicación con GeneXus, el primer paso consiste en crear un nuevo proyecto o base de conocimiento.

Una vez creada una nueva base de conocimiento (en inglés: knowledge base; abreviado: KB), el siguiente paso es describir las visiones de los usuarios. Para ello se deben identificar los objetos de la realidad (prestando atención a los sustantivos que los usuarios mencionan en sus descripciones, como por ejemplo: clientes, productos, facturas) y pasar a definirlos mediante objetos GeneXus.

Con la definición de estos objetos, GeneXus puede extraer el conocimiento y diseñar la base de datos y los programas de la aplicación en forma automática.

Page 7: Aplicaciones Genexus

5

Desarrollo con GeneXus

REALIDAD

DESCRIPCIÓNDE OBJETOS

BASE DECONOCIMIENTO

Utilizando GeneXus, la tarea básica del analista es la descripción de la realidad. Sólo el ser humano puede desarrollar esta tarea ya que sólo él puede entender el problema del usuario.

El analista GeneXus trabaja en alto nivel, en vez de realizar tareas de bajo nivel como: diseñar archivos, normalizar, diseñar programas, programar, buscar y eliminar los errores de los programas.

Para comenzar el desarrollo de una aplicación con GeneXus, el primer paso consiste en crear un nuevo proyecto o base de conocimiento.

Una vez creada una nueva base de conocimiento (en inglés: knowledge base; abreviado: KB), el siguiente paso es describir las visiones de los usuarios. Para ello se deben identificar los objetos de la realidad (prestando atención a los sustantivos que los usuarios mencionan en sus descripciones, como por ejemplo: clientes, productos, facturas) y pasar a definirlos mediante objetos GeneXus.

Con la definición de estos objetos, GeneXus puede extraer el conocimiento y diseñar la base de datos y los programas de la aplicación en forma automática.

Page 8: Aplicaciones Genexus

6

REALIDAD

Desarrollo con GeneXus

DESCRIPCIÓNDE OBJETOS

BASEDE

DATOS

PROGRAMAS

BASE DECONOCIMIENTO

A partir de los objetos definidos en la base de conocimiento, GeneXus genera automáticamente tanto los programas de creación / reorganización de la base de datos como los programas de la aplicación.

Luego, si un objeto de la realidad cambia, si se identifican nuevas o diferentes características del mismo, o si se encuentran objetos aún no modelados, el analista GeneXus debe reflejar dichos cambios en los objetos GeneXus que correspondan, y la herramienta se encargaráautomáticamente de realizar las modificaciones necesarias tanto en la base de datos como en los programas asociados.

La metodología GeneXus es una metodología incremental, pues parte de la base de que la construcción de un sistema se realiza mediante aproximaciones sucesivas.

En cada momento el analista GeneXus define el conocimiento que tiene y luego cuando pasa a tener más conocimiento (o simplemente diferente) lo refleja en la base de conocimiento y GeneXus se ocupará de hacer automáticamente todas las adaptaciones en la base de datos y programas.

Si GeneXus no fuera capaz de realizar automáticamente las modificaciones en la base de datos y programas conforme se realicen cambios que así lo requieran, el desarrollo incremental sería inviable.

Page 9: Aplicaciones Genexus

7

Data Providers(DP)

Procedimientos(Procs)

Web Panels(Wbps)

Algunos objetos GeneXus

Transacciones(Trns)

y hay más, que veremos...

Una vez creada una base de conocimiento, el siguiente paso consiste en comenzar a describir los objetos de la realidad mediante objetos GeneXus.

Los objetos GeneXus más importantes son:

Transacciones Permiten definir los objetos de la realidad que el usuario manipula (ej: clientes, productos, proveedores, facturas, etc.). Son los primeros objetos en definirse, ya que a través de las transacciones, GeneXus infiere el diseño de la base de datos.Además de tener por objetivo la definición de la realidad y la consecuente creación de la base de datos normalizada, cada transacción tiene asociada una pantalla para ambiente windows y otra para ambiente Web, para permitir al usuario dar altas, bajas y modificaciones en forma interactiva a la base de datos. El analista GeneXus decidirá si trabajar en ambiente windows, Web, o ambos, y GeneXus generará los programas para ello.

ProcedimientosPermiten recuperar información de la base de datos, y desplegarla ya sea en la pantalla, en un archivo o impresa en papel. Son los típicos listados o informes. Además, permiten la actualización de la información de la base de datos.

Data ProvidersPermiten cargar y devolver datos jerárquicos para intercambio de información entre objetos de la misma aplicación o de otras aplicaciones.

Web PanelsPermiten al usuario realizar interactivamente consultas a la base de datos, a través de una pantalla. Ejemplo: un web panel permite al usuario ingresar un rango de caracteres, y muestra a continuación todos los clientes cuyos nombres se encuentran dentro del rango.Son objetos web muy flexibles que se prestan para múltiples usos. No permiten la actualización de la base de datos, sino solo su consulta.

Page 10: Aplicaciones Genexus

8

Proceso de desarrollo de unaaplicación con GeneXus

Base de ConocimientoBase de Conocimiento

BaseBasede de

DatosDatos

Data Providers(DP)

Procedimientos(Procs)

Web Panels(Wbps)

Transacciones(Trns)

Los primeros objetos que se definen son las transacciones, ya que es a partir de ellas que GeneXus extrae el conocimiento necesario para diseñar el modelo de datos normalizado (en 3era. forma normal). Luego se van definiendo los demás objetos que correspondan.

Page 11: Aplicaciones Genexus

9

Creación de la Base de Datos

BaseBasede de

DatosDatos

Programas Creación

BD

Base de ConocimientoBase de Conocimiento

Data Providers(DP)

Procedimientos(Procs)

Web Panels(Wbps)

Transacciones(Trns)

GeneXus genera automáticamente los programas necesarios para crear la base de datos y los ejecuta. De esta manera obtenemos la base de datos creada por GeneXus en forma automática.

Page 12: Aplicaciones Genexus

10

Programas de Aplicación

(Trns, Procs, Wbps, DPs, etc.)

Generación de los Programas de la aplicación

BaseBasede de

DatosDatos

Base de ConocimientoBase de Conocimiento

Data Providers(DP)

Procedimientos(Procs)

Web Panels(Wbps)

Transacciones(Trns)

Luego, GeneXus genera programas de aplicación para interactuar con la base de datos previamente creada.

Page 13: Aplicaciones Genexus

11

Resultado final en la Etapa de Desarrollo

BaseBasede de

DatosDatos

Base de ConocimientoBase de Conocimiento

Programas de Aplicación

(Trns, Procs, Wbps, DPs, etc.)

Data Providers(DP)

Procedimientos(Procs)

Web Panels(Wbps)

Transacciones(Trns)

Una vez creada la base de datos y generados los programas, contamos con una aplicación pronta para ejecutar.

Page 14: Aplicaciones Genexus

12

Las visiones de los usuarios cambian

Nueva Nueva BaseBasede de

DatosDatos

BaseBasede de

DatosDatos

Programas de Aplicación

(Trns, Procs, Wbps, DPs, etc.)

NuevosProcedimientos

NuevosData Providers

NuevosWeb Panels

NuevaNuevaBaseBasede de

DatosDatos

NuevasTransacciones

Base de ConocimientoBase de Conocimiento

Durante el ciclo de vida de la aplicación, surgirá repetidamente la necesidad de hacer modificaciones en la base de conocimiento, ya sea porque las visiones de los usuarios cambian, porque se deben hacer correcciones, o simplemente agregar nuevo conocimiento.

Las modificaciones que se realicen sobre la base de conocimiento serán analizadas por GeneXuspara evaluar si es necesario efectuar cambios en la base de datos (por ejemplo: modificación/creación de tablas/índices), o no.

En caso de detectar cambios para efectuar en la base datos, GeneXus detallará los mismos en un reporte de análisis de impacto (IAR: Impact Analisis Report), que es un reporte que explicita todos los cambios sobre tablas, índices, datos, etc. que habría que realizar para reflejar la nueva realidad.

Asimismo, en el reporte de análisis de impacto se informan los eventuales problemas que los cambios en cuestión podrían ocasionar, como inconsistencias o redundancias.

Page 15: Aplicaciones Genexus

13

Análisis de Impacto Automático

Análisisde

impacto

Nueva Nueva BaseBasede de

DatosDatos

BaseBasede de

DatosDatos

Programas de Aplicación

(Trns, Procs, Wbps, DPs, etc.)

NuevaNuevaBaseBasede de

DatosDatos

Base de ConocimientoBase de Conocimiento

NuevosProcedimientos

NuevosData Providers

NuevosWeb Panels

NuevasTransacciones

Algunas veces la nueva base de datos coincide con la anterior. Otras veces esto no ocurre, y la base de datos debe sufrir alguna modificación para representar la nueva realidad.

El analista debe estudiar el reporte de análisis de impacto y resolver si desea realizar efectivamente los cambios en la base de datos, o renunciar a ello dejando la base de datos como estaba.

Page 16: Aplicaciones Genexus

14

Generación de Programas de Reorganización de la Base de Datos

Programasde

Reorganiz.

Programas de Aplicación

(Trns, Procs, Wbps, DPs, etc.)Nueva Nueva BaseBasede de

DatosDatos

BaseBasede de

DatosDatos

NuevaNuevaBaseBasede de

DatosDatos

Base de ConocimientoBase de Conocimiento

NuevosProcedimientos

NuevosData Providers

NuevosWeb Panels

NuevasTransacciones

Si el analista opta por aplicar los cambios propuestos, decimos que optó por reorganizar la base de datos. Utilizamos este término para referirnos a la acción de aplicar cambios físicos sobre la base de datos.

GeneXus generará los programas que implementan las modificaciones sobre las estructuras físicas de la base de datos, y mediante su ejecución nos brindará la nueva versión de la base de datos con los cambios efectuados.

Page 17: Aplicaciones Genexus

15

Análisis automático del impactode los cambios sobre los programas

Análisisde Impacto sobre los programas

Nuevos Programas de Aplicación

(Trns, Procs, Wbps, DPs, etc.)

NuevaNuevaBaseBasede de

DatosDatos

Base de ConocimientoBase de Conocimiento

NuevosProcedimientos

NuevosData Providers

NuevosWeb Panels

NuevasTransacciones

Ya sea que se requiera reorganizar la base de datos o no, considerando las nuevas definiciones introducidas, GeneXus estudiará el impacto de los cambios sobre los programas actuales.

Page 18: Aplicaciones Genexus

16

Generación automática de nuevos programas

NuevaNuevaBaseBasede de

DatosDatos

Nuevos Programas de Aplicación

(Trns, Procs, Wbps, DPs, etc.)

Generación de

programas

Base de ConocimientoBase de Conocimiento

NuevosProcedimientos

NuevosData Providers

NuevosWeb Panels

NuevasTransacciones

Por último, GeneXus proseguirá con la generación/regeneración de los programas de aplicación que sean necesarios, obteniendo así una nueva versión de la aplicación.

Page 19: Aplicaciones Genexus

17

Nueva realidad, con los cambios en la aplicación

NuevaNuevaBaseBasede de

DatosDatos

Nuevos Programas de Aplicación

Base de ConocimientoBase de Conocimiento

NuevosProcedimientos

NuevosData Providers

NuevosWeb Panels

NuevasTransacciones

De modo que nuevamente contaremos con una aplicación pronta para ejecutar, con los cambios aplicados.

Page 20: Aplicaciones Genexus

18

• El lugar donde se almacena la información para generar la aplicación en cierta plataforma de ejecución se llama Environment.

• El uso de varios Environments permite distintas implementaciones de la misma aplicación.

C# & SQL Server

C# & MySQL

Java & MySQL

GeneXusProject

Knowledge Base

Environments:Implementation #1

Implementation #2C# Application

MySQL

C# Application

SQL

Implementation #3Java Application

MySQL

Environments

Page 21: Aplicaciones Genexus

19

• Cuando se crea una base de conocimiento (KB), GeneXus pide al usuario que seleccione el Environment con el que va a trabajar:

• Con estos datos, se crea automáticamente un ‘Environment’.

Environments

Para crear una base de conocimiento, se debe seleccionar en la barra de menú de GeneXus, el ítem File / New Knowledge Base. A continuación aparecerá un diálogo como el siguiente:

Se deberá indicar;

• Nombre de la Knowledge Base: en nuestro caso será BillingSystem.• Directorio donde se creará.• El ‘Environment’ por defecto: vea como se muestran lenguajes de programación. GeneXus los utilizará para crear los programas asociados a la base de datos. Las opciones ofrecidas son: C# Environment, Java Environment y Ruby Environment.• Language: Idioma en el que aparecerán los botones, mensajes, etc.

Al momento de crear la KB se comienza a definir el ambiente de implementación (Environment) cuyas definiciones serán luego completadas al momento de ejecutar la aplicación (nombre de la base de datos, servidor, forma de conexión, etc).

Page 22: Aplicaciones Genexus

20

• Para ver el ‘Environment’ creado, seleccionamos la ventana de Preferences del Knowledge Base Navigator:

DefaultEnvironment

Environments

Page 23: Aplicaciones Genexus

21

Environments• Para tener implementaciones en distintas plataformas, creamos 

varios ‘Environments’.

Page 24: Aplicaciones Genexus

22

• Vemos los ‘Environments’ creados:

Environments

C# & SQL Server

Java & MySQL

GeneXusProject

Knowledge Base

Environments:

El environment activo está señalado en negrita y tiene el ícono de “Play”

Page 25: Aplicaciones Genexus

23

Construir una aplicación mediante aproximaciones sucesivas.

DEFINICION INICIAL

Metodología Incremental

La construcción automática de la base de datos y programas, permite a GeneXus aplicar esta metodología de desarrollo, conocida como metodología incremental.

Como ya hemos explicado, este proceso se realiza mediante aproximaciones sucesivas.

Page 26: Aplicaciones Genexus

24

Metodología Incremental

Para aplicar un desarrollo incremental, puedo manejar distintas versiones de la aplicación.

• Versión para prototipación.

• Versión para poner en producción.

Sobre el versionado (de qué se trata, cómo realizarlo, etc.) volveremos al final. Por ahora alcanza con saber que al crear la base de conocimiento, los programas que estaremos ejecutando, programas reales, serán una versión de la aplicación, de prueba. Una vez que decidamos que esa versión estálista para ser puesta en producción, alcanzará con hacer otra ‘versión’ de la aplicación, y ¡listo!.

Page 27: Aplicaciones Genexus

25

Ventajas de la Prototipación

• Permite ver resultados en forma temprana.

• Permite el seguimiento de los requerimientos del usuario.

• Detección de errores en forma temprana.

• Logra el compromiso de los usuarios con el desarrollo.

• Sistemas de mejor calidad.

Toda comunicación es susceptible de errores:

• El usuario olvida ciertos detalles• El analista no toma nota de algunos elementos• El usuario se equivoca en algunas apreciaciones• El analista malinterpreta algunas explicaciones del usuario

Como la implementación de sistemas es habitualmente una tarea que insume bastante tiempo, y muchos de estos problemas sólo son detectados en las pruebas finales del sistema, el costo en tiempo y dinero de solucionarlos se torna muy grande. Sabido es que la realidad no permanece estática, por lo que no es razonable suponer que se pueden mantener congeladas las especificaciones mientras se implementa el sistema. Sin embargo, debido al tiempo que suele insumir la implementación, muchas veces esto se hace y se acaba implementando una solución relativamente insatisfactoria.

El impacto de estos problemas disminuiría mucho si se consiguiera probar cada especificación inmediatamente y saber cuál es la repercusión de cada cambio sobre el resto del sistema. Una primera aproximación a esto, ofrecida por diversos sistemas, es la posibilidad de mostrar al usuario formatos de pantallas, informes, etc., animados por menús. Esto permite ayudar al usuario a tener una idea de quésistema se le construirá, pero al final siempre se presentan sorpresas.

Una situación bastante diferente sería la de poner a disposición del usuario para su ejecución, una aplicación funcionalmente equivalente a la deseada hasta en los mínimos detalles. Y esto es lo que ofrece GeneXus! Un prototipo GeneXus es una aplicación pronta funcionalmente equivalente a la aplicación de producción.

Así es que la aplicación puede ser totalmente probada antes de ponerse en producción; y durante las pruebas, el usuario final puede probar de una forma natural no solamente formatos de pantallas, informes, etc., sino también fórmulas, reglas del negocio, estructuras de datos, etc., y trabajar con datos reales.

Esto solo es posible gracias a la construcción automática que realiza GeneXus del soporte computacional (base de datos y programas).

Page 28: Aplicaciones Genexus
Page 29: Aplicaciones Genexus

26

Objeto Transacción

El análisis de toda aplicación GeneXus comienza con el diseño de las transacciones.

Las transacciones permiten definir los objetos de la realidad.

Para identificar cuáles transacciones deben crearse, se recomienda prestar atención a los sustantivos que el usuario menciona cuando describe la realidad.

Además de tener por objetivo la definición de la realidad y la consecuente creación de la base de datos normalizada, las transacciones, al igual que la mayoría de los objetos GeneXus que estudiaremos, provocan la generación de programas. En particular los programas correspondientes a las transacciones tienen por objeto permitir dar altas, bajas y modificaciones en forma interactiva en las tablas que tengan implicadas, controlando estos programas la integridad referencial de los datos.

Page 30: Aplicaciones Genexus

27

TransaccionesGeneralidades

Definición Objeto a partir del cual GeneXus creará en forma automática la base de datos en 3era forma normal

• Describen las visiones de los usuarios.

• Contienen toda la información necesaria acerca de los datos de la aplicación y de cómo los usuarios accederán al sistema para su manejo (insertar, modificar y eliminar).

Elementos que las componen:

Algunos elementos de las transacciones, que iremos viendo son:

Estructura: Permite definir los atributos (campos) que componen la transacción y la relación entre ellos. A partir de la estructura de las transacciones, GeneXus inferirá el diseño de la base de datos: tablas, claves, índices, etc.

Web Form: Cada transacción contiene un Form (pantalla) Web mediante el cual se realizarán las altas, bajas y modificaciones en ambiente Web.

Reglas: Las reglas permiten definir el comportamiento particular de las transacciones. Por ejemplo, permiten definir valores por defecto para los atributos, definir chequeos sobre los datos, etc.

Eventos: Las transacciones soportan la programación orientada a eventos. Este tipo de programación permite definir código ocioso, que se activa en respuesta a ciertas acciones provocadas por el usuario o por el sistema.

Variables: Permite la definición de variables que serán locales a la Transacción.

Propiedades: Permiten definir ciertos detalles referentes al comportamiento de la transacción.

Documentación: Permite la inclusión de texto técnico, para ser utilizado como documentación del sistema.

Ayuda: Permite la inclusión de texto de ayuda, para ser consultado por los usuarios en tiempo de ejecución de la transacción.

Category y Work With: Patterns (patrones) que pueden ser aplicados a la Transacción con el fin de implementar en forma automática cierta funcionalidad.

Algunos de estos elementos también están asociados a otros tipos de objetos GeneXus.

Page 31: Aplicaciones Genexus

28

Ejemplo: Se necesita registrar información de proveedores.

Se define transacción “Supplier”, con estructura:

{SupplierId* Identificador de proveedorSupplierName Nombre de proveedorSupplierAddress Dirección de proveedorSupplierPhone Teléfono de proveedor

}

TransaccionesEstructura

La estructura de una transacción permite definir qué atributos la integran y cómo están relacionados.

A modo de ejemplo, si en una aplicación se necesita registrar información de proveedores, claramente habrá que definir una transacción, a la que podemos dar el nombre “Supplier”, y su estructura podría ser la siguiente:

{SupplierId*SupplierNameSupplierAddressSupplierPhone }

Esta lista de nombres (uno de los cuales está sucedido del símbolo asterisco) corresponde a los atributos que interesa mantener acerca de los proveedores.

Entonces, creamos una transacción de nombre “Supplier” cuya estructura se compone de los atributos SupplierId, SupplierName, SupplierAddress y SupplierPhone.

Esto significa que cada proveedor se identificará por un código SupplierId (lo que queda determinado por el asterisco a continuación del atributo1), tendrá un nombre SupplierName, una dirección SupplierAddressy un teléfono SupplierPhone.

Para cada atributo definido en la estructura, deberemos indicar cosas tales como su tipo de datos, descripción y algunos detalles más que veremos.

--------------------------------------------------------------------------------------------------------------1 El asterisco corresponde a una notación teórica que utilizamos para indicar que el atributo es identificador. Como veremos, nuestro asterisco en GeneXus aparece representado por un ícono de llave y el usuario podrá configurarlo mediante un menú contextual que le ofrecerá esta posibilidad.

Page 32: Aplicaciones Genexus

29

Vista de la estructura en GeneXus:

TransaccionesEstructura

Atributos ClaveEn la página anterior hemos explicado que el asterisco a continuación del atributo SupplierId indica que se trata del identificador de la transacción. Toda transacción debe tener un identificador, esto es, un atributo o conjunto de atributos que definan la unicidad.

En el ejemplo no podrán existir dos proveedores con el mismo valor de SupplierId. En definitiva se trata del concepto de clave primaria, en tanto, para hacer la elección de los atributos que la componen, se deben tener en cuenta los requisitos del objeto de la realidad.

En los casos en los cuales no se pueda determinar un identificador, se debe optar por crear un atributo artificial (no existente en la realidad), y que su valor se asigne internamente, por ejemplo, en forma correlativa.

Como se puede observar en el editor de transacciones de GeneXus, un ícono de llave representa el asterisco que nosotros utilizamos como notación teórica.

Atributo “descriptor”El ícono con una lupa representa al atributo que mejor describe o representa a la transacción. En otras palabras sería el atributo que tiene mayor carga semántica en la transacción.

Por defecto el primer atributo en la estructura de la transacción que sea de tipo de datos character, se definirácomo “atributo descriptor”. Es posible definir a otro atributo como descriptor utilizando el menú popup correspondiente, así como no definir ninguno.

Page 33: Aplicaciones Genexus

30

Ejemplo: Se necesita registrar información referente a facturas de venta.

TransaccionesEstructura

Invoice{

InvoiceId* Identificador de facturaInvoiceDate Fecha de facturaCustomerId Identificador de clienteCustomerName Nombre de cliente

Detail{

ProductId* Identificador de productoProductDescription Descripción de productoProductPrice Precio de productoInvoiceDetailQuantity Cantidad de producto llevada en la líneaInvoiceDetailAmount Importe de línea de factura

}InvoiceAmount Importe total de la factura

}

Niveles de una transacciónLa transacción “Invoice” consta de dos niveles: el primer nivel queda implícito por lo que no necesita un juego de llaves; el segundo nivel corresponde al conjunto de atributos que se encuentra entre llaves1.El hecho de definir un segundo nivel significa que existen varias instancias del mismo, para cada instancia del nivel anterior. En el ejemplo, un cabezal de factura tiene varios productos.Cada nivel de una transacción define un grupo de atributos que deben operar en conjunto, es decir, se ingresan, se eliminan o se modifican conjuntamente en la base de datos.

Llamaremos transacción plana a una transacción de un solo nivel. Así, la transacción “Supplier” es una transacción plana.

En cambio, la transacción “Invoice” tiene dos niveles. Es común hablar de “cabezal” para referirnos al primer nivel y de “líneas” para referirnos al segundo.

Para cada nivel de la transacción, se debe indicar cuáles de sus atributos actúan como identificador. El identificador de cada nivel puede estar compuesto de un solo atributo, como es el caso de las transacciones que hemos visto hasta ahora, o puede estar conformado por varios atributos.

En la transacción “Invoice” el atributo InvoiceId es el identificador del primer nivel, y el atributo ProductIdes el identificador del segundo nivel. Esto último significa que para un número de factura dado, InvoiceId, no puede repetirse el valor del atributo ProductId en distintas líneas.

Una transacción puede contener varios niveles paralelos, así como anidados.

--------------------------------------------------------------------------------------------------------------1 Al igual que el asterisco es una notación teórica que representa que el atributo que lo antecede es identificador en la transacción, el juego de llaves también es utilizado como notación teórica, para representar que los atributos contenidos forman parte de un nivel anidado, y que tiene una representación visual en GeneXus distinta, pero que indica lo mismo.

Page 34: Aplicaciones Genexus

31

Vista de la estructura en GeneXus

TransaccionesEstructura

En GeneXus queda visualmente claro el nivel correspondiente a las líneas de la factura.A cada nivel de una transacción se le debe asignar un nombre, tipo1 y descripción (salvo al primer nivel, que recibe como nombre el de la transacción).

Niveles paralelos y anidadosUna transacción puede tener varios niveles de anidación, así como niveles paralelos.Por ejemplo, en el hipotético caso de que una factura pueda abonarse en varios pagos, podríamos definir dos tipos de estructura, dependiendo de lo que se quiera representar:

Invoice { Invoice {InvoiceId* InvoiceId*

InvoiceDate InvoiceDateCustomerId CustomerIdCustomerName CustomerNameInvoiceAmount InvoiceAmount

Detail Detail{ProductId* {ProductId*ProductDescription ProductDescriptionProductPrice ProductPriceInvoiceDetailQuantity InvoiceDetailQuantityInvoiceDetailAmount} InvoiceDetailAmountPayment Payment

{InvoicePaymentDate* {InvoicePaymentDate*InvoicePaymentAmount} InvoicePaymentAmount}}

} }

Con la estructura de la izquierda se define que una factura tiene muchos productos y muchos pagos, pero no hay una relación directa entre los productos y los pagos (a no ser el hecho de pertenecer a la misma factura). En la estructura de la derecha se registran los pagos por producto llevado.Es sencillo comprender que el segundo y tercer nivel de la transacción de la izquierda, son paralelos. Ambos se encuentran anidados al primer nivel, pero entre ellos, son paralelos. En la estructura de la derecha, son todos niveles anidados.-------------------------------------------------------------------------------------------------------------------1 Como veremos luego, el tipo que se define para un nivel de una transacción, será utilizado para trabajar con businesscomponents, concepto relacionado a las transacciones.

Page 35: Aplicaciones Genexus

32

Invoice{

InvoiceId*InvoiceDateCustomerIdCustomerName

Detail{

ProductId*ProductDescriptionProductPriceInvoiceDetailQuantityInvoiceDetailAmount

}InvoiceAmount

}

Definición del modelo de datos: estructuras de las transacciones

TransacciónTransacción

Supplier{SupplierId*SupplierNameSupplierAddressSupplierPhone

}

TablaSUPPLIER

SupplierId*SupplierNameSupplierAddressSupplierPhone

Transacciones

InvoiceId*ProductId*ProductDescriptionProductPriceInvoiceDetailQuantityInvoiceDetailAmount

TablaINVOICEDETAIL

InvoiceId*InvoiceDateCustomerIdCustomerNameInvoiceAmount

TablaINVOICE

GeneXus utiliza la estructura de las transacciones para capturar el conocimiento necesario para definir automáticamente cuál es el modelo de datos que debe crear.

Para poder realizar la normalización de la base de datos llevándola a 3era. forma normal, GeneXus debe extraer las dependencias funcionales existentes entre los atributos definidos en la base de conocimiento.

En la base de conocimiento de nuestro ejemplo, hemos definido a la transacción “Proveedores” y de su estructura GeneXus extrae las siguientes dependencias funcionales:

SupplierId {SupplierName, SupplierAddress, SupplierPhone}

Dadas estas dependencias funcionales, GeneXus determina que debe crear una tabla que tendrá por defecto el mismo nombre que la transacción (SUPPLIER)1, y que estará conformada ni más ni menos que por los cuatro atributos anteriores, siendo SupplierId la clave primaria de la misma:

Diremos que la transacción “Supplier” tiene asociada la tabla SUPPLIER en el entendido de que cuando se ingresen, modifiquen o eliminen datos por medio de la transacción, éstos se estarán almacenando, modificando o eliminando físicamente en la tabla asociada.

------------------------------------------------------------------------------------------------------------1 En la documentación, para distinguir el nombre de una tabla del nombre de una transacción escribiremos el nombre de la tabla todo en mayúscula.

SUPPLIER SupplierId SupplierName SupplierAddress SupplierPhone

Page 36: Aplicaciones Genexus

33

A partir de la estructura de la transacción “Invoice”, GeneXus determina que debe crear dos tablas:

Tabla INVOICE, correspondiente al primer nivel de la transacción:

Clave primaria: InvoiceId

Tabla INVOICEDETAIL correspondiente al segundo nivel de la transacción:

Clave primaria: {InvoiceId, ProductId}Clave foránea: InvoiceId

ya que las dependencias funcionales son:

InvoiceId {CustomerId, CustomerName, InvoiceDate, InvoiceAmount}{InvoiceId, ProductId} {ProductDescription, ProductPrice, InvoiceDetailQuantity,

InvoiceDetailAmount}

Observemos que la clave primaria de la tabla INOVICELINE es la concatenación del identificador del primer nivel, InvoiceId, con el identificador del segundo nivel, ProductId. El caso es general: la clave primaria de la tabla correspondiente a un nivel n de una transacción se obtiene de concatenar los identificadores de los n-1 niveles anteriores anidados, con el identificador de ese nivel.

GeneXus asigna un nombre predeterminado a las tablas que crea. A la tabla asociada al primer nivel de una transacción le asigna el mismo nombre que el de la transacción; y a las tablas de niveles subordinados les asigna la concatenación de los nombres de los niveles. Por esto es que la tabla asociada al segundo nivel de la transacción “Invoice” recibe el nombre INVOICEDETAIL, dado que el nombre del primer nivel es el de la transacción, INVOICE, y el del segundo nivel es DETAIL. Los nombres de las tablas pueden ser modificados por el analista GeneXus cuando así lo desee.

INVOICE InvoiceId CustomerId CustomerName InvoiceDate InvoiceAmount

INVOICEDETAIL InvoiceId ProductId ProductDescription ProductPrice

InvoiceDetailQuantity InvoiceDetailAmount

Page 37: Aplicaciones Genexus

34

Customer{CustomerId*CustomerNameCustomerAddressCustomerGender

}

Al definir las nuevas transacciones:

Product{ProductId*ProductDescriptionProductPriceProductStock

}Sexo del cliente

TransaccionesEstructura

Luego de haber modelado la transacción “Invoice”, nos damos cuenta que hay información de clientes y de productos que nos interesa mantener independientemente de las facturas. Es decir, los clientes y los productos son dos objetos de la realidad independientes de las facturas, por lo tanto creamos las dos nuevas transacciones “Customer” y “Product” detalladas arriba.

Dependencias funcionalesCon estas nuevas transacciones definidas, aparecen nuevas dependencias funcionales:

CustomerId {CustomerName, CustomerAddress, CustomerGender, CustomerStatus}ProductId {ProductDescription, ProductPrice, ProductStock}

que conducen directamente a la creación de dos nuevas tablas:

Clave primaria: CustomerId

y:

Clave primaria: ProductId

CUSTOMER CustomerId CustomerName CustomerAddress CustomerGender

PRODUCT ProductId ProductDescription ProductPrice ProductStock

Page 38: Aplicaciones Genexus

35

InvoiceId*InvoiceDateCustomerIdCustomerNameInvoiceAmount

TablaINVOICE

InvoiceId*ProductId*ProductDescriptionProductPriceInvoiceDetailQuantityInvoiceDetailAmount

TablaINVOICEDETAIL

TablaSUPPLIER

SupplierId*SupplierNameSupplierAddressSupplierPhone

Tabla CUSTOMER

CustomerId*CustomerNameCustomerAddressCustomerGender

Tabla PRODUCT

ProductId*ProductDescriptionProductPriceProductStock

TransaccionesNormalización: cambios en las tablas

El conjunto total de dependencias funcionales existentes requiere que deban realizarse algunas modificaciones en las tablas INVOICE e INVOICEDETAIL diseñadas previamente para que el diseño de la base de datos permanezca en 3era. forma normal1.

Si representamos sobre las tablas CUSTOMER e INVOICE las dependencias funcionales encontradas para sus atributos:

podemos ver claramente que INVOICE viola la 3era. forma normal (existe una dependencia funcional transitiva):

InvoiceId CustomerIdCustomerId CustomerNameInvoiceId CustomerName

por lo tanto GeneXus normaliza, quitando el atributo CustomerName de la tabla INVOICE:

Ahora CustomerName solo estará en la tabla CUSTOMER.-------------------------------------------------------------------------------------------------------------------1 Por más información sobre las formas normales (3era. forma normal, etc.) le recomendamos la lectura del documento “Fundamentos de bases de datos relacionales”, el cual está incluido en el capítulo de “Anexos” del curso GeneXus no presencial. De lo contrario, puede pedírselo al docente.

Page 39: Aplicaciones Genexus

36

Ahora veamos las dependencias funcionales encontradas en las tablas PRODUCT e INVOICEDETAIL:

podemos percibir claramente que la tabla INVOICEDETAIL está violando la 3era. forma normal (existen atributos que están dependiendo en forma parcial de la clave primaria):

ProductId ProductDescription ProductId ProductPrice{InvoiceId, ProductId} ProductDescription {InvoiceId, ProductId} ProductPrice

Por lo tanto GeneXus normaliza, quitando los atributos ProductDescription y ProductPrice de la tabla INOVICEDETAIL:

ProductDescription y ProductPrice solo quedarán en la tabla PRODUCT.

Page 40: Aplicaciones Genexus

37

Relaciones: establecidas por los nombres de atributosTransacciones

• Conceptos iguales deben tener igual nombre

• Conceptos diferentes NO deben tener igual nombre

Invoice {

InvoiceId*CustomerIdCustomerName...

}

Customer{

CustomerId*CustomerName

}

Invoice {

InvoiceId*InvoiceCustomerId...

}

Customer{

CustomerId*CustomerName

}

Invoice {

InvoiceId*DateCustomerIdCustomerName...

}

VendorInvoice{

VendorInvoiceId*DateSupplierId*SupplierName...

}

incorrecto

Conceptos iguales deben tener el mismo nombre y conceptos diferentes deben ser nombrados diferentes. GeneXus establece las relaciones a través de los nombres de los atributos, de modo que cuando encuentra atributos de igual nombre en distintas transacciones, entiende que se trata del mismo concepto, y mediante dicho conocimiento es que puede normalizar.

En el ejemplo que venimos viendo, cuando GeneXus encuentra el atributo de nombre CustomerId tanto en la transacción “Customer” como en la transacción “Invoice”, analiza que: el atributo se llama igual en ambas transacciones, así que se refiere al mismo concepto. En la transacción “Customer”, CustomerIdestá marcado como identificador, lo que significa que será clave primaria en la tabla física CUSTOMER; entonces en la tabla física INVOICE será clave foránea.

El atributo CustomerName, por su parte, también se encuentra tanto en la transacción “Customer”como en la transacción “Invoice”, pero a diferencia de CustomerId, no está marcado como identificador en ninguna transacción del modelo; por tanto GeneXus entiende que se trata de un atributo secundario. Las dependencias funcionales indican que a CustomerName lo determina CustomerId:

InvoiceId CustomerIdCustomerId CustomerName

así que GeneXus incluirá CustomerName en la tabla física CUSTOMER (y no en la tabla física INVOICE).

Atributos primarios y secundariosUn atributo se califica como primario cuando el mismo es identificador en alguna transacción del modelo. En el ejemplo que venimos viendo, CustomerId es un atributo primario ya que es identificador en la transacción “Customer”.

CustomerName, en cambio, es un atributo secundario ya que no es identificador en ninguna transacción del modelo.

Page 41: Aplicaciones Genexus

38

Atributos almacenados e inferidos

Al definir las transacciones “Customer” y “Product”, hemos incluido en ellas ciertos atributos que no hemos eliminado de la transacción “Invoice”.

Los atributos CustomerId y ProductId, se incluyeron en las transacciones “Customer” y “Product”respectivamente, y al ser denotados como identificadores de las mismas, pasaron a ser atributos primarios. El atributo CustomerName, por su parte, se agregó en la transacción “Customer”; y los atributos ProductDescription y ProductPrice se incluyeron en la transacción “Product”. Estos son atributos secundarios.

Todos estos atributos han quedado en más de una transacción: se han dejado en la transacción “Invoice” tal como se habían definido en un principio, y se han incluido en las transacciones “Customer”y “Product” respectivamente, porque nos hemos percatado de la necesidad de crear estos objetos.

A continuación presentamos las 3 estructuras de las transacciones en cuestión, para poder visualizarlas juntas:

Probablemente usted no comprenda la razón por la cual los atributos secundarios CustomerName, ProductDescription y ProductPrice se han dejado en la estructura de la transacción “Invoice”.

La explicación es la siguiente: las estructuras de las transacciones no son equivalentes a estructuras de tablas físicas. En las estructuras de las transacciones se pueden incluir ciertos atributos que no estarán en la o las tablas físicas asociadas, ya que a la hora de reorganizar la base de datos GeneXus analizará el conjunto total de dependencias funcionales existentes en la base de conocimiento, y creará -o modificará, según el caso- las tablas físicas, dejándolas en 3ª forma normal.

Ahora, ¿con qué finalidad hemos dejado los atributos secundarios CustomerName, ProductDescriptiony ProductPrice en la estructura de la transacción “Invoice”? Los hemos dejado para poder incluirlos en alguno de los forms (GUI-Windows y/o Web) asociados a la transacción “Invoice” y así poder visualizar los valores de dichos atributos en tiempo de ejecución.

Dichos atributos, como hemos explicado, no quedarán almacenados ni en la tabla INVOICE, ni en la tabla INVOICEDETAIL; sin embargo, en tiempo de ejecución cuando el usuario ingrese a través dealguno de los forms (GUI-Windows y/o Web) un valor de CustomerId (atributo que sí se almacenará en la tabla INVOICE siendo clave foránea), a continuación se mostrará el CustomerNamecorrespondiente. Decimos que el atributo CustomerName es un atributo inferido en la transacción “Invoice”, ya que su valor no se encuentra almacenado en ninguna de las tablas asociadas a la transacción, sino que se infiere –es decir, se obtiene- de la tabla CUSTOMER, dado el valor del atributo CustomerId.

Análogamente, los atributos ProductDescription y ProductPrice también son inferidos en la transacción “Invoice”, ya que no se encuentran almacenados en las tablas asociadas a la misma, sino que sus valores se infieren de la tabla PRODUCT, para ser mostrados en pantalla.

Invoice{

InvoiceId*InvoiceDateCustomerIdCustomerName

Detail{ ProductId*ProductDescriptionProductPriceInvoiceDetailQuantityInvoiceDetailAmount}InvoiceAmount

}

Customer{

CustomerId*CustomerNameCustomerAddressCustomerGender

}

Product{

ProductId*ProductDescriptionProductPriceProductStock

}

Page 42: Aplicaciones Genexus

39

Es conveniente usar padrones para los nombres de los atributos.

• Facilitan la tarea de nombrado.

• Facilitan la tarea de integración de bases de conocimiento.

• Facilitan la lectura del código generado.

TransaccionesEstructura: nombrado de atributos

Page 43: Aplicaciones Genexus

40

Nomenclatura GIKComponente de Entidad + CategorComponente de Entidad + Categoríía [+ Calificador + Complemento]a [+ Calificador + Complemento]

…y en inglés:

TransaccionesEstructura: nombrado de atributos

Entity Component Qualifier Category

Customer Id

Customer Name

Customer Start Date

Customer End Date

Invoice Id

Invoice Due Date

InvoiceDetail Amount

VendorInvoice id

Entity Component Category Qualifier

Cliente Id

Cliente Nombre

Cliente Fecha Inicial

Cliente Fecha Final

Factura Id

Factura Fecha Vencimiento

FacturaDetalle Cantidad

FacturaCompra Id

Artech ha definido un estándar para la nomenclatura de atributos: el GeneXus Incremental Knowledge Base (GIK) que es utilizado por la comunidad de usuarios GeneXus.

En esta nomenclatura, el nombre de un atributo se forma con 4 componentes (algunos opcionales, señalados entre paréntesis rectos):

Componente de Entidad + Categoría [+ Calificador + Complemento] 1

A continuación describimos en qué consiste cada componente:

Componente de Entidad (u Objeto):Una Entidad es un actor (ej: Customer), objeto o evento (ej: Vendor Invoice, factura de venta) que interviene en una aplicación dada, representado por una transacción Genexus2. Un Componente de Entidad, representa a cualquier nivel subordinado o paralelo que defina la entidad.

Ejemplo: la factura tiene los siguientes componentes, Invoice (cabezal), InvoiceDetail (líneas de la solicitud).Se sugiere un largo de un entorno de 10 caracteres para representar el componente de la Entidad.

Categoría: Es la categoría semántica del atributo, es decir, define el rol que el mismo asume dentro del objeto y dentro del entorno de la aplicación. Se sugiere que no supere los 10 caracteres.

Ejemplos: Id (identificador), Code (código), Name (nombre), Date (fecha), Description (descripción), Price (precio), Stock.

--------------------------------------------------------------------------------------------------------------1 Para países que utilicen lenguas en las que los adjetivos suelan colocarse después del sustantivo. En el inglés esto es al revés, por lo que la categoría (el sustantivo) va al final. 2 O un conjunto de Transacciones paralelas y/o subordinadas, de las que hablaremos más adelante.

Page 44: Aplicaciones Genexus

41

Calificador: Es cualquier adjetivo o adverbio, en el entorno de 10 caracteres, que agregue diferenciación conceptual al nombre del atributo para hacerlo único.En general refiere al texto que califica la categoría: Fecha de vencimiento, Ejemplos: Start (inicial), End (final), Due (vencimiento)

Complemento: Texto libre hasta completar la cantidad de caracteres significativos (30) para el nombre.

En la transparencia se muestran algunos ejemplos de nombres de atributos.

Nota 1: Las letras mayúsculas permiten establecer fronteras entre los componentes que forman a los nombres de atributos.

Nota 2: Para cada componente se pueden utilizar la cantidad de caracteres que se deseen, aunque se sugiere utilizar 10 y que el nombre completo del atributo no supere los 30.

Page 45: Aplicaciones Genexus

42

Demo

• Una vez creada la base de conocimiento: creación de las primeras transacciones.

Una vez creada la base de conocimiento (ver introducción teórica), la misma quedará abierta para que se empiecen a crear las transacciones.

La creación de objetos, se realiza presionando Ctrl+N. Los objetos creados quedarán en la carpeta Objects que se puede ver en la Folder View de la ventana KB Navigator.Si se desea que el objeto a crear quede guardado en otra carpeta, se deberá posicionar en dicha carpeta y luego hacer clic con el botón derecho del mouse. En el menú elegir New Object.También se podrá indicar la carpeta en el cuadro de creación de un objeto como se ve en la imagen.

Se desplegará un diálogo en el cual se deberá elegir el tipo de objeto que se desea crear (en este caso el tipo de objeto: Transaction), dar un nombre al objeto que se está creando (por ejemplo: “Customer” o “Invoice”), una descripción larga, y la carpeta en la cual guardar el objeto.

Una vez creada la transacción, la misma quedará abierta para que se defina su estructura y dentro de ella sus atributos.

Page 46: Aplicaciones Genexus

43

TransaccionesDefinición de atributos

F4

Para definir un atributo, simplemente se debe digitar en el primer campo de una línea (o rama) de la estructura, el nombre del atributo que se desea crear. Mediante la tecla de tabulación se puede pasar a los siguientes campos para indicar el tipo de datos del atributo, así como su descripción, si admitirá valores nulos de la base de datos, y en el caso que el mismo vaya a ser una fórmula (concepto que veremos en breve), cómo calcularla. Con la tecla Enter se puede pasar a la siguiente línea, para definir otro atributo.

Una vez definidos los atributos en la estructura de la transacción, solamente restará guardar / salvar los cambios.

Si se necesita modificar el nombre de un atributo, su tipo de datos, descripción, nulabilidad, o fórmula, bastará con hacer doble clic sobre el campo implicado en la estructura, y el mismo se habilitará y se podráeditar. Luego se deberán guardar los cambios, nuevamente.

Para indicar que uno o más atributos son identificadores en la transacción, se los debe seleccionar y presionar CTRL + K; en consecuencia aparecerán con un símbolo de llave.

Para definir que comienza otro nivel en la transacción, se debe digitar CTRL + L, y automáticamente se producirá una indentación y el usuario deberá darle nombre a ese nivel, así como definir el nombre de su tipo de datos1 y una descripción para el nivel.

Para indicar que un atributo de uno de los niveles de la transacción será el atributo “descriptor”, se lo debe seleccionar y presionar CTRL+D.

GeneXus cuenta con menús pop up2, que son menús que se abren cuando el usuario está posicionado en determinado contexto y da clic con el botón derecho del mouse. Por ejemplo, al hacer clic con el botón derecho del mouse sobre un atributo de la estructura, se abre un menú pop up sobre el atributo seleccionado, que ofrece varias utilidades, como por ejemplo indicar que el atributo es clave (opción “Toggle key”), quitarlo de la estructura, pasarlo a un siguiente nivel de anidación, etc.

Cada atributo tiene propiedades. Algunas de ellas (las fundamentales y obligatorias) son las que se ofrecen directamente en la estructura para su ingreso “inline”. Para acceder al diálogo que permite configurar todas las propiedades de un atributo, se debe seleccionar el ítem Properties del menú contextual, o presionar la tecla F4. En la figura hemos cambiado la propiedad Autonumber que como veremos oportunamente, permite autonumerar atributos clave primaria.

----------------------------------------------------------------------------------------------------1 Veremos su utilidad cuando estudiemos los “business components”.2 También llamados “contextuales” dado que varían según el contexto.

Page 47: Aplicaciones Genexus

44

Name: Es el nombre del atributo. Se utiliza para identificarlo.

Description: La “Descripción” o más propiamente “Nombre largo” es una descripción ampliada del atributo. Debe identificar bien al atributo, con independencia del contexto, y principalmente debe ser entendible por el usuario final. Debe ser un identificador global del atributo, es decir, no se le debe asignar a dos atributos en la base de conocimiento la misma descripción, ya que será a través de esta descripción que el usuario final podrá seleccionar atributos para definir sus propias consultas a la base de datos, con el objeto de tipo query, ejecutando “reportes dinámicos” (tema bastante simple, pero que no se abordará en este curso).

Relacionadas a esta propiedad, están las propiedades Title, Column Title y Contextual Title. Las 2 primeras por defecto toman el mismo valor que se especifica en Description, pudiéndose modificar:

Title: La descripción que se ingrese aquí será colocada por defecto al lado del atributo cada vez que se utilice en salidas “planas” como en el primer nivel de los forms de las transacciones (veremos en breve los forms).

Column Title: La descripción que se ingrese aquí será colocada por defecto como título del atributo cada vez que se lo incluya en la columna de un grid (grilla) (en el caso de una transacción solo si se trata de un atributo inferido, como por ejemplo el atributo ProductDescription en la transacción Invoice)1.

Contextual Title: Cuando el atributo pertenece al segundo nivel de una transacción, y no es inferido (ejemplo InvoiceDetailQuantity en Invoice), el nombre de la columna del grid de la transacción será tomado de esta propiedad. Obsérvese que por defecto se toma de la propiedad Description, pero quitando el nombre de la transacción, pues se asume del “contexto”.

Type DefinitionBased on: Permite asociarle un dominio2 al atributo. Al hacerlo, ciertas propiedades del atributo se

deshabilitarán (como Data Type y Length) tomando los valores del dominio. En caso de que el atributo nopertenezca a un dominio, el programador dejará el valor ‘(none)’ en esta propiedad, y las correspondientes al tipo de datos del atributo estarán habilitadas para ser ingresadas.

Data Type: Permite indicar el tipo de datos del atributo. Aquí se podrá elegir uno de los tipos de datos soportados por GeneXus. Dependiendo del tipo de datos que se seleccione habrá ciertas propiedades, u otras, para configurar.

Length: Permite indicar el largo del atributo. Si en la propiedad Data Type se indica que el atributo es numérico, entonces se deberá tener en cuenta que el largo incluya las posiciones decimales, el punto decimal y el signo. Esta propiedad estará deshabilitada cuando el tipo de datos elegido no requiera establecer un largo (por ejemplo, si se trata del tipo de datos Date).

Decimals: Si en la propiedad Data Type se indica que el atributo es numérico, se ofrecerá esta propiedad, para que se especifique la cantidad de decimales. El valor 0 en este campo, indicará que se trata de un entero.

Signed: Si en la propiedad Data Type se indica que el atributo es numérico, se ofrecerá esta propiedad para que se indique si manejará signo o no. El valor por defecto es “False”, lo que indica que no se representarán valores negativos.

ValidationValue Range: Permite indicar un rango de valores válidos para el atributo. Por ejemplo:· 1:20 30: - significa que los valores válidos son entre 1 y 20; y 30 o mayor.

· 1 2 3 4 - significa que los valores válidos son 1, 2, 3 o 4.· 'S' 'N' - significa que los valores válidos son 'S' o 'N'.

PicturePermite indicar el formato de edición para la entrada y salida del atributo. Dependiendo del tipo de datos del

atributo, aparecerán determinadas propiedades bajo esta categoría.

GeneXus provee más propiedades para los atributos que las recién mencionadas. Dependiendo del valor que se elija para determinada propiedad, se ofrecerán ciertas propiedades relacionadas, u otras. Recomendamos para la lectura de otras propiedades, acceder al Help de GeneXus.

-------------------------------------------------------------------------------------------------------------------------------1 El atributo también podrá estar en un objeto Web Panel. En ese caso, de aparecer como columna, siempre se ofrecerá por defecto para el nombre de la misma el de su propiedad ColumnTitle2 Los dominios se abordarán unas páginas más adelante en el curso, pero a modo de resumen, el objetivo de los dominios es realizar definiciones de datos genéricas. Por ejemplo: se puede definir un dominio de nombre Precio y tipo de datos Numeric(10,2) y luego asociarle este dominio a todos los atributos que almacenan precios. Esto tiene la ventaja de que si después se desea modificarlo a por ejemplo Numeric(12,2), hay que modificar solamente la definición del dominio y automáticamente todos los atributos basados en ese dominio heredan el cambio.

Page 48: Aplicaciones Genexus

45

Control Info

A un atributo se le puede asociar un tipo de control. Los tipos de controles posibles son:- Edit- Radio Button- Check Box- Combo Box- List Box- Dynamic Combo Box- Dynamic List Box

La asociación de cierto tipo de control a un atributo, sirve para especificar el tipo de control por defecto que se utilizarápara el atributo cada vez que se lo incluya en un form.

Cuando se define un atributo con un tipo de datos básico, el tipo de control que tiene asociado es Edit, pudiendo elprogramador cambiarlo a cualquiera de los otros tipos. En general GeneXus elige el tipo de control para un atributo dependiendo de su tipo de datos. Si es un dominio enumerado, como veremos, elegirá Radio Button o Como Box, dependiendo de la cantidad de valores del dominio.

En el grupo Control Info del diálogo de edición de las propiedades de un atributo es donde el programador podrácambiar el tipo de control asociado al atributo y dependiendo del tipo de control seleccionado, se solicitará distinta información complementaria.

Luego, cada vez que se agregue el atributo en un form se presentará automáticamente con el tipo de control que tenga asociado aquí.

Nota

En caso de asociar al atributo el tipo Edit, se podrá especificar que “disfrace” sus valores, mostrando los de otro atributo (propiedad InputType), e incluso que sugiera los valores posibles al usuario, a medida que éste vaya digitando (propiedad Suggest), entre otras, como veremos luego, cuando estudiemos “Descripciones en lugar de códigos”.

También se puede elegir el color de la fuente de letra que se desea asociar por defecto al atributo, así como el color de fondo, de modo que cada vez que se agregue el atributo en un form, se presente automáticamente con los colores que se le hayan asociado (ver grupo Appearance).

Page 49: Aplicaciones Genexus

46

• Numeric, Character, Date, Boolean

• VarChar- Equivalente a Character, salvo en la forma en que se almacena

en la BD.- Propiedades Maximum Length y Avarage Length asociadas.

• Long Varchar- Permite almacenar textos largos, comentarios, etc. (memo).

• DateTime - Permite almacenar una combinación de fecha y hora.

• Blob- Permite almacenar cualquier tipo de información: texto,

imágenes, videos, planillas, etc., en la base de datos.

TransaccionesAtributos: Tipos de Datos

Numeric: Permite almacenar datos numéricos. Cuando se selecciona este tipo de datos se debe indicar la cantidad total de dígitos del número, la cantidad de posiciones decimales, y si permite signo o no.

Ejemplo: Si definimos que el tipo de datos del atributo InvoiceAmount es numérico de largo 10, con decimales 2, y sin signo, estamos especificando que representará números con hasta 7 dígitos en la parte entera y 2 decimales (7 dígitos en la parte entera + punto + 2 dígitos para los decimales = 10 dígitos).

Character: Permite almacenar cualquier tipo de texto (caracteres y dígitos). Para este tipo de datos, se debe indicar el largo.

Ejemplo: El atributo CustomerName que utilizamos para almacenar el nombre de un cliente, es de tipo Character y si sabemos que nunca un nombre tendrá más de 20 caracteres, podemos fijar el largo: 20.

Date: Permite almacenar una fecha. Ejemplo: El atributo InvoiceDate que utilizamos para almacenar la fecha de una factura, será de este tipo de datos.El formato a utilizar para las fechas (día-mes-año, mes-día-año), se configura en forma genérica para todo el modelo dentro de un tipo especial de objeto, el objeto Language correspondiente al lenguaje en el que se generará el modelo. El objeto “language” existe para poder tener una misma aplicación traducida en cualquier lenguaje.La elección de presentar el año con 2 dígitos o 4, se configura con la propiedad Picture de cada atributo.

• Boolean: permite que un atributo o variable asuma los valores lógicos: True, False.

Page 50: Aplicaciones Genexus

47

• VarChar: Permite almacenar texto de largo variable. Su función, en contraposición al Character, es optimizar el almacenamiento en la base de datos. Cuando se selecciona el tipo de datos VarChar en el diálogo de definición del atributo se agregan las 2 siguientes propiedades: Maximum Length y Average Length. La primera es para indicar el largo máximo de caracteres que se podrán almacenar, mientras que la segunda es para indicar el largo promedio de caracteres que se suele almacenar por lo general. Ejemplo: Cuando se define un atributo de tipo Character y largo 60, si se le ingresa un dato que ocupa 25 caracteres, la capacidad restante de almacenamiento del atributo (35 caracteres) se rellena con blancos. El tipo de datos Varchar, en cambio, optimiza el almacenamiento de la siguiente forma: se le define Average Length (por ejemplo: 25), y Maximum Length (por ejemplo: 60); entonces, si el dato tiene largo menor o igual que 25, se lo almacena en el campo (rellenado con blancos) mientras que en los casos que el dato sea de largo mayor que 25, se almacenan los primeros 25 caracteres en el campo, y el resto en un área de overflow.Como contrapartida a la ventaja de la optimización del almacenamiento, para los casos en que se utilice el área de overflow, será necesario realizar un acceso adicional tanto para la lectura como para la escritura del dato. El tipo de datos Varchar es equivalente al tipo Character en todos los sentidos, salvo en la forma en que se almacena en la base de datos. Se le pueden aplicar todas las funciones y operadores existentes para el tipo de datos Character. Si el DBMS no soporta este tipo de datos, se creará el atributo de tipo Character.

Long Varchar: Permite definir un atributo memo; es decir, se utiliza normalmente para almacenar textos largos, comentarios, etc. Al seleccionar este tipo de datos, se debe indicar un largo máximo. Existen dos funciones para manipular este tipo de datos: GXMLines y GXGetMLi.

GXMLines retorna la cantidad de líneas que tiene un atributo Long Varchar, teniendo como parámetros el nombre del atributo, y la cantidad de caracteres que se desea considerar por línea.

Ejemplo: &cantlin = GXMLines( AtribMemo, 40 ).

GXGetMLi por su parte, extrae una línea del atributo Long Varchar (para luego imprimirla, por ejemplo); teniendo como parámetros el nombre del atributo, el número de línea deseado, y la cantidad de caracteres que se desea considerar por línea.

Ejemplo: &txt = GXGetMLi( AtribMemo, 1, 40 ).

Generalmente se usan estas 2 funciones en combinación, ya que primero se suele consultar la cantidad de líneas que tiene cierto atributo Long Varchar, indicando la cantidad deseada de caracteres por línea, y luego se prosigue extrayendo el contenido de las líneas, utilizando un bucle hasta llegar a la última línea, y de esta forma se imprimen, por ejemplo.

DateTime: Permite almacenar una combinación de fecha y hora.

La propiedad Picture de este tipo de datos, permite elegir qué se desea mostrar de la fecha, y qué se desea mostrar de la hora.

Acerca de la fecha se puede elegir: no manejarla, manejarla y presentar el año con 2 dígitos, o manejarla y presentar el año con 4 dígitos. Acerca de la hora se puede elegir: manejar solo 2 dígitos para la hora (no manejando minutos ni segundos), manejar 2 dígitos para la hora y 2 dígitos para los minutos (no manejando segundos), o manejar 2 dígitos para la hora, 2 dígitos para los minutos y 2 dígitos para los segundos.

Los valores anteriores no afectan la forma de almacenar el tipo de datos sino específicamente la forma de aceptar o mostrar su contenido.Nota: En caso de no manejar la fecha, sino solo la hora, el valor de fecha que quedará en el campo será el mínimo soportado por el DBMS, y será reconocido por GeneXus como fecha vacía o nula. En lo que respecta a la hora, los valores no aceptados (minutos y/o segundos) serán almacenados con valor cero.

Blob: Ante el creciente manejo de imágenes digitalizadas, videos, planillas así como documentos de todo tipo, las aplicaciones requieren cada vez más mantener y trabajar con este tipo de información.El tipo de datos Blob permite almacenar esta diversidad de información en la propia base de datos, aprovechando así los diferentes mecanismos de integridad y control que proveen los DBMSs.Este tipo de datos solamente se puede utilizar cuando se cuenta con un DBMS.

Para profundizar en el conocimiento de este tipo de datos puede dirigirse al Help de GeneXus.

Page 51: Aplicaciones Genexus

48

• En todo objeto GeneXus es posible definir variables.

• Las variables son únicamente visibles dentro del objeto; es decir, son locales.

• Editor similar al de la estructura de las transacciones:

TransaccionesDefinición de variables

• Es posible definir variables colección (de cualquier tipo de datos).

Para definir variables en determinado objeto, se debe seleccionar el selector Variables, como se muestra en la figura.Este selector muestra variables definidas por defecto (Standard variables, como por ejemplo la variable Today que contiene la fecha del sistema) para el objeto, y permite definir variables nuevas a través de un editor similar al de las transacciones.

También se puede ir a la opción Insert de la menubar y elegir Variables. En el cuadro de diálogo que se desplegará seleccionar New Variable.

Este diálogo solicita el nombre de la variable, su descripción, tipo de datos y largo, o dominio, de forma análoga a cuando se define un atributo.La propiedad Dimensions permite indicar si la variable será escalar o si se tratará de un vector (1 dimensión) o matriz (2 dimensiones). El valor que ofrece por defecto esta propiedad es escalar.

Page 52: Aplicaciones Genexus

49

TransaccionesDefinición de variables

• Comparten varias propiedades con los atributos:• Data Type: aunque no todo tipo de datos 

válido para atributo también lo es para variable (ej: Blob) y viceversa (ej: tipos de datos estructurados).

F4

Based OnOfrece una forma rápida de definir una variable. Cuando se selecciona, se despliega un diálogo que muestra todos los atributos (y dominios) definidos en la base de conocimiento; en dicho diálogo, simplemente se debe seleccionar un atributo, y a continuación se definirá automáticamente una variable con el mismo nombre y la misma definición que el atributo.

Por otra parte, es posible definir variables dentro del editor de código de cada objeto (source, eventos, etc.), haciendo uso del menú contextual (botón derecho) luego de escribir el nombre de la variable. Esto es, al escribir &nombreDeVariable y presionar botón derecho del mouse. En el menú contextual luego elegir Add Variable.

Variables colecciónEs posible definir variables colección sobre cualquier tipo de datos ofrecido por GeneXus.Para eso alcanza con clickear la correspondiente casilla en el editor de variables, o indicar el valor True en la propiedad Collection asociada a las variables.Para recorrer luego los items coleccionados en dicha variable, se deberá utilizar la estructura de control “For in”.

Por ejemplo, hemos definido la variable &myNumbers de tipo Numeric(4.0)Para recorrer los valores almacenados se deberá crear una nueva variable de tipo Numeric(4.0). Creamos entonces la variable &OneNumber, y declaramos:

For &OneNumber in &myNumbers----------

Endfor

Page 53: Aplicaciones Genexus

50

• Objetivo: Realizar definiciones genéricas.

• ¿Cuándo debemos usar dominios?• Atributos y/o variables con la misma definición.

Ejemplo:

Atributos

Dominios

InvoiceDetailAmount Importe total de línea

ProductPrice Precio de producto

TransaccionesDominios

Es común tener en una base de conocimiento atributos que comparten definiciones similares pero que no tienen relación entre sí. Por ejemplo, es común definir todos los nombres como atributos de tipo character y largo 20; o todos los importes, como atributos de tipo numérico y largo 10.2.

El objetivo de los dominios es permitir realizar definiciones genéricas. A modo de ejemplo, el atributoInvoiceDetailAmount es de tipo numérico y largo 10.2, y al mismo tiempo, el atributo ProductPrice es del mismo tipo y largo, en la misma base de conocimiento. De modo que podríamos definir un dominio de nombre Price, que sea de tipo numérico con largo 10.2, y luego uno Amount de tipo de datos el dominio Price anterior; a cada uno de los atributos anteriores le asignaríamos estos dominios. La ventaja de hacerlo así es que si en el futuro surge la necesidad de cambiar la definición de los atributos que representan importes, haríamos el cambio una sola vez (en el dominio Price), propagándose éste automáticamente a los atributos InvoiceDetailAmount y ProductPrice.

Page 54: Aplicaciones Genexus

51

• Dominios enumerados: queremos mantener el estado del cliente: Active, On Hold, Closed  dominio Status 

TransaccionesDominios

Luego atributo CustomerStatus de dominio StatusSe trabaja con los nombres en lugar de con los valores:

CustomerStatus = Status.Active

Existe la posibilidad de trabajar con dominios enumerados (aquellos que representan valores finitos y particulares. Son muy conocidos en los lenguajes de programación. El caso de uso típico es para los días de la semana: cuando se necesita que una variable tome uno de los siguientes valores: Lunes, Martes, Miércoles, Jueves, Viernes, Sábado, Domingo).

En nuestro caso, agregaremos a la estructura de la transacción Customer, un atributo que representa el estado del cliente en el sistema en un momento dado. Puede estar active, on hold o closed.

Una forma de representarlo es definiendo un dominio Status, que corresponde al tipo de datos Character(1) pero para el que decimos explícitamente que no queremos que pueda tomar todos los valores de ese tipo de datos, sino solo 3: A, H y C, y además le decimos que queremos trabajar dándole nombres a estos 3 valores y trabajar con sus nombres. Así, a A le asociamos el nombre ‘Active’, a H ‘OnHold’ y a C ‘Closed’. Al asociarle al atributo CustomerStatus el dominio Status (observar que GeneXus automáticamente lo sugiere al ingresar el atributo en la estructura luego de haber definido el dominio, debido a la terminación del nombre del atributo) internamente en el atributo de la tabla se guardará uno de los 3 valores: A, H o C, pero nosotros no tendremos que recordar esos valores, sino sus códigos: Active, OnHold y Closed.

Ya teníamos otro atributo con dominio enumerado: CustomerGender. En ese caso se componía de solamente 2 valores: Female y Male.

Observar cómo el Control Info ofrece para ControlType un Combo Box en lugar de un Edit. Esto tomará sentido cuando veamos el Form de una transacción un poco más adelante.

Page 55: Aplicaciones Genexus

52

TransaccionesDominios

Así como podemos asociarle a un atributo un dominio (y a otro dominio), también lo podemos hacer para una variable. Un mismo dominio puede asignarse tanto a atributos como a variables, ya que su objetivo es exactamente el mismo.

¿Cómo definir un dominio?Existen varios caminos:1) Opción Domains de el Folder View: Mediante un editor similar al de las variables, se podrá definir un nuevo dominio. 2) Dado que en la pantalla de configuración de las propiedades de un atributo es donde se le asigna a un atributo un dominio existente, en dicha pantalla se ofrece un botón para crear un dominio nuevo. Ídem con el diálogo de definición de variables.3) En la estructura de la transacción es posible definir un nuevo domino en el campo de definición del tipo de datos de un atributo, simplemente escribiendo sobre esa misma línea, el nombre del dominio, y asignándole el tipo de datos. Por ejemplo, digitando Price = Numeric(10.2) sobre la columna Type del atributo que se estádefiniendo, queda también definido el dominio de nombre Price, con el tipo de datos Numeric(10.2).

Page 56: Aplicaciones Genexus

53

• Cada transacción tiene asociado un Web Form.

• Es creado por defecto al grabar la estructura de la transacción, pudiendo ser modificado por el programador.

TransaccionesWeb Form

Para cada transacción, GeneXus crea un form web, que será la interfaz con el usuario.

Es creado por defecto por GeneXus al momento de grabar la estructura de la transacción, y contienen todos los atributos incluidos en la misma, con sus respectivas descripciones, además de algunos botones.

Si bien es creado por defecto, es posible modificarlo para dejarlo más vistoso, cambiar por ejemplo controles de tipo edit a otros tipos de controles, agregar y/o quitar botones, etc.

Page 57: Aplicaciones Genexus

54

GRID

Control “Error Viewer”

TransaccionesWeb Form de la transacción “Invoice”

En el ejemplo se muestra el form Web correspondiente a la transacción “Invoice”. A través de este form el usuario final podrá ingresar, modificar y eliminar facturas en la aplicación Web.

El control Error Viewer se utiliza para poder ubicar y programar el lugar donde queremos que los mensajes generales le sean desplegados al usuario final de una transacción Web.

Podremos especificar entre otras cosas el lugar donde queremos que este control se ubique dentro del form, su tipo de letra, color, etc.

Observar que el segundo nivel de la transacción aparece en el form como un control grid.

Page 58: Aplicaciones Genexus

55

TransaccionesWeb Form de la transacción “Customer”

Dominios enumerados controles Combo Box

Dominios básicos controles Edit

Page 59: Aplicaciones Genexus

56

Insertar controles:

Cortar, copiar y pegar controles:

TransaccionesPaletas de herramientas para el diseño de Forms

• Opción View de la Menubar \ Other Tool Windows \Toolbox

Podemos definir un control como un área de la interfaz con el usuario, que tiene una forma y un comportamiento determinado.Existen distintos controles:

- Texto: Permite colocar texto fijo - Atributo/Variable: Permite colocar atributos o variables.- Línea horizontal- Error Viewer- Table: Insertar tablas en el form- Grid: Permite definir grillas de datos.- Botón: Permite incluir botones en los forms. - Bitmap: Permite definir bitmaps estáticos, etc.

Paleta de herramientas para insertar controles: Cuando se está editando un form, se encuentra disponible una paleta de herramientas (Toolbox) que ofrece los controles posibles de insertar en el mismo. Simplemente se deberá seleccionar el control y arrastrarlo sobre el form.

Page 60: Aplicaciones Genexus

57

• Cada control del Web form podrá tener una clase asociada, de un objeto theme (tema) determinado, asociado al objeto.

TransaccionesControles en Web Form

• Al crear una KB, se crea por defecto el tema “GenexusX” y todos los objetos que se creen tendrán este tema asociado.

• Esto permitirá independizar el diseño de la interfaz, de la programación.

• Cada tema tendrá definidas muchas clases para cada tipo de control.

• El analista solo asocia un tema al objeto, y una clase a cada control del form y puede olvidarse del diseño de los mismos.

• El control hereda el diseño de la clase del tema al que esté asociado.

Para lograr separar los aspectos de diseño gráfico de un sitio web, de los aspectos de programación propiamente dichos, existe un tipo de objeto llamado Theme (Tema, en español).

El objetivo de esta separación es poder paralelizar el desarrollo de un sitio Web, permitiéndole al programador abocarse a las tareas de programación, y apoyarse en un diseñador gráfico para que defina las cuestiones de diseño. De esta manera el diseñador gráfico configurará el “tema” elegido por el programador, y el programador sólo deberá aplicarlo a los objetos de su base de conocimiento.Un objeto “tema” contendrá un conjunto de clases, para cada tipo de control de los que pueden aparecer en el form Web de un objeto GeneXus. Por ejemplo, tendrá varias clases para el control botón, algunas para el control atributo, una clase para el control Error Viewer, etc.

Cuando se crea una base de conocimiento, automáticamente aparecerá dentro del Folder View la carpeta “Customization” con objetos Theme predefinidos que podrán importarse en la KB. Por defecto se importa el de nombre “GeneXusX”. Este tema contiene un conjunto de clases asociadas a los distintos controles existentes.

Los objetos con form Web que se vayan creando tendrán por defecto asociado este Theme, y cada controlque aparezca en sus forms tendrá asociado una clase de ese tema, para este control.

Page 61: Aplicaciones Genexus

58

TransaccionesControles en Web Form

De este modo, cuando el analista crea la transacción “Customer” e ingresa su estructura, al grabar podráapreciar que el form Web tendrá automáticamente el aspecto que se muestra en la pantalla de arriba a la izquierda. ¿Quién dio formato a todos los controles si no lo hizo el analista explícitamente?

Pues bien, todas las transacciones tendrán asociado por defecto el theme “GeneXusX” y todos los controles que se coloquen en el form, tendrán clases de este tema asociadas.

Si sobre el Text Block (control de texto) que se muestra arriba (Name), se editan sus propiedades (F4), se puede observar la propiedad Class, que tiene configurada la clase TextBlock. Esta propiedad puede ser cambiada por el analista. Al cliquear el combo box podremos ver una lista de clases posibles para ese control (son las que figuran en el tema asociado). A la derecha hemos cambiado la clase por una de nombre Title y en el form podemos ver la repercusión en el diseño del TextBlock.

No entraremos en detalle en este tema en el presente curso.

Page 62: Aplicaciones Genexus

59

Demo

¿Cómo ejecutar la aplicación?

Opción Build \ Run Developer Menu, o presionar la tecla F5.

F5: Dispara automáticamente todas las acciones necesarias para ejecutar la aplicación

Si BD no existe, se crea automáticamente (siempre y cuando usuario y password tengan permisos de DBCreator)

Recordemos que al momento de creación de la KB, se indicó el generador por defecto a utilizar. Ahora se debe completar la información necesaria para terminar de definir el ambiente de implementación.

Database name: Nombre de la base de datos que estará asociada a la aplicación.

Server name: Nombre del servidor de base de datos que la manejará.

Use trusted connection: YesNo (deberá indicarse usuario y contraseña válido en el DBMS)

Consideraciones:

Si la base de datos no existiera, GeneXus la creará, siempre y cuando el usuario y contraseña configurados en la ventana de diálogo tengan permiso de DBCreator en el DBMS.

Page 63: Aplicaciones Genexus

60

Proceso de Build

El proceso de Build incluye todas las tareas necesarias para la ejecución de la aplicación: Verificación de cambios en la BD, Reorganización (si es necesario), Especificación, Generación y Compilación. No incluye la ejecución.

KB

SPECIFICATION

GENERATION

COMPILATION

REORGANIZATION

DBASE IMPACT ANALYSIS

APPLICATION

Aplicación pronta para ejecutar

El proceso de Build se ejecuta en background, permitiendo realizar otras tareas mientras el mismo está corriendo, por ejemplo continuar con el desarrollo.

Cada vez que se ejecuta la aplicación (F5), GeneXus realiza una comparación entre las definiciones actuales de todos los objetos y las definiciones de la última ejecución. Esta comparación se llama análisis de impacto. Este nombre es autodescriptivo: GeneXus analiza el impacto causado por las nuevas definiciones, y el resultado del análisis de impacto es un reporte de análisis de impacto (IAR: Impact Analisis Report) que informa al programador qué cambios físicos o estructurales habría que realizar en la base de datos asociada.

Si por ejemplo se creó una nueva transacción, esto provocará (tal como es el objetivo de las transacciones) que se creen las tablas correspondientes en la base de datos (ver siguiente página).

Page 64: Aplicaciones Genexus

61

IAR y Reorganización

‘Create’ si está todo OK se construirán los programas en el Environment y se ejecutará...

En el ejemplo, tras crear las 2 transacciones “Customer” e “Invoice” y dar F5, aparece el reporte de análisis de impacto que puede verse, donde se listan entre otras cosas, la estructura que tendrá cada tabla que se creará, con sus atributos, tipos de datos, los índices que se crearán sobre las tablas, las claves foráneas (observar que el reporte de la tabla INVOICE dice que se referenciará la tabla CUSTOMER (esto se debe al atributo CustomerId de la transacción Invoice que se llama igual que el atributo CustomerId de CUSTOMER, constituyendo por tanto una clave foránea a dicha tabla).

Si el programador está de acuerdo con los cambios estructurales informados en el reporte de análisis de impacto, podrá proseguir, pasando a reorganizar la base de datos. El término reorganizar refiere a efectuar cambios físicos en la base de datos.

Si en cambio el programador encuentra que algo de lo informado en el reporte de análisis de impacto no era lo que pretendía lograr, podrá no efectuar la reorganización, y efectuar en cambio las redefiniciones que crea convenientes.

Cuando se decide efectuar una reorganización GeneXus genera programas (en el lenguaje elegido cuando se creó la KB) que implementan las modificaciones a realizar en la base de datos. La ejecución de estos programas tiene por resultado la obtención de una nueva versión de la base de datos con los cambios efectuados.

El siguiente paso será obtener los programas de aplicación asociados a los objetos GeneXus. Para ello GeneXus deberá especificar, generar y compilar los programas de aplicación.

Especificar un objeto significa que GeneXus analizará todo lo definido en cada uno de los elementos que lo componen: estructura, forms, u otros elementos según corresponda. GeneXus verificará la sintaxis de las definiciones, la validez de lo definido, y como resultado de la especificación mostrará al usuario un listado de navegación, en el cual informará la lógica que ha interpretado, y si hay alguna advertencia o error.

Generar un objeto, significa que GeneXus escribirá líneas de código que implementen la programación del mismo, en el lenguaje elegido.

Compilar los programas significa que el código escrito (generado) sea convertido a lenguaje máquina (binario) para que puedan ser ejecutados.

Page 65: Aplicaciones Genexus

62

Ejecución

Page 66: Aplicaciones Genexus

63

Opción “Build” de la barra demenú de GeneXus

Opciones del ítem “Build”:

• Build All y Rebuild All: Estas opciones se utilizan cuando no se está seguro del impacto de los cambios y se necesita tener actualizadas las últimas definiciones. La opción Build All realiza todas las acciones que estén pendientes, mientras que Rebuild All forzará todas ellas.Las acciones son:

- Salvar todos los objetos que no estén salvados.- Reorganizar la base de datos, si es necesario.- Especificar solo los objetos que han sido modificados (si se seleccionó Build All), o

forzar la especificación de todos (si se seleccionó Rebuild All).- Generar los objetos- Compilar los objetos definidos Main- Compilar el Developer Menu

• Build / Rebuild Developer Menu: Similar a las opciones anteriores pero aplicadas solamente al Developer Menu. No lo ejecuta.

• Run Developer Menu: Ejecuta todas las acciones que estén pendientes y ejecuta el Developer Menu.

- Salva todos los objetos que no estén salvados.- Reorganizarla base de datos, si es necesario.- Especifica solo los objetos que han sido modificados.- Genera los objetos- Compila y ejecuta el Developer Menu

Page 67: Aplicaciones Genexus

64

• Build / Rebuild / Run options: Opciones que aplican a objetos definidos como Main. Disparan las siguientes acciones:

- Salvan los objetos que no estén salvados.- Reorganizan la base de datos, si es necesario.- Se especifican solamente los objetos que sufrieron cambios (si se seleccionó Build), o se

fuerza la especificación de todos los objetos pertenecientes al árbol de llamadas delobjeto Main (si se seleccionó Rebuild).

- Generación- Compilación del objeto Main- Ejecución del objeto Main (si se seleccionó la opción Run)

• Build / Run with this only options: Build y ejecución del objeto definido como Startup. Por defecto el objeto Startup es el Developer Menu.

- Salvan todos objetos que no estén salvados.- Reorganizan la base de datos, si es necesario.- Especifican solamente el objeto seleccionado.- Generan solamente el objeto seleccionado.- Compilan el objeto Startup- Se ejecuta el objeto Startup (si se seleccionó Run).

• Set As Startup Object: El objeto indicado pasará a ser el objeto Startup de la aplicación, o sea el objeto que finalmente se ejecutará cuando se presione la tecla F5. Por defecto el objeto Startup es el Developer Menu.

• Create Database Tables: Crea nuevamente las tablas. Se pierden los datos que pudieran estar almacenados previamente.

• Impact Database Tables: Se realiza un impacto sobre las tablas de la base de datos.

Page 68: Aplicaciones Genexus

65

• Al ejecutar una transacción se pueden distinguir los siguientes modos, dependiendo de la operación que se realice:

Modo Insert: Indica que se está efectuando una inserción

Modo Update: Indica que se está efectuando una actualización

Modo Delete: Indica que se está efectuando una eliminación

Modo Display: Indica que se está efectuando una consulta

TransaccionesModos en tiempo de ejecución

Dependiendo del ambiente de generación, habrá algunas diferencias en lo que se refiere a la operativa de las transacciones en tiempo de ejecución. No obstante, más allá de la plataforma, cada vez que se realice una operación de inserción, actualización, eliminación, o consulta a la base de datos a través de una transacción, habrá un modo asociado.

Page 69: Aplicaciones Genexus

66

TransaccionesEn tiempo de ejecución

&GxRemove:Variable del sistema para eliminar líneas.

Para agregar una nueva línea

Siempre se mostrará un número de líneas vacías fijas para ser ingresadas por el usuario (valor configurable por el analista a nivel del grid, en su propiedad “Rows”). Por defecto se muestran 5 líneas vacías.Si el usuario ingresó las 5 líneas y necesita ingresar más, le bastará con presionar New Row., o simplemente presionar Enter y se agregará una nueva línea.

Para poder eliminar líneas en ejecución, GeneXus incorpora automáticamente en el grid del form Web una primera columna conformada una variable del sistema de nombre &GxRemove, en forma de check box. Para visualizar este check box, se debe presionar el botón derecho del mouse sobre la línea a eliminar. Luego se deberá presionar el botón Confirm.

Page 70: Aplicaciones Genexus

67

TransaccionesMaster Pages

Las Master Pages proveen una forma de centralizar el layout y el comportamiento común en un solo objeto y reutilizarlo en todo otro objeto sin tener que programar.

Creadas automáticamente con la KB

Tener un look & feel consistente es hoy en día un deber de toda aplicación Web.Crear y mantener cada página de una aplicación Web asegurando la consistencia con el resto del sitio toma gran tiempo de programación.

Al crear una base de conocimiento GeneXus X creará también dos objetos de tipo Master Page:AppMasterPage: Para la aplicación.PromptMasterPage: Para los prompts.

Las Master Pages proveen una forma de centralizar el layout y el comportamiento común en un solo objeto y reutilizarlo en todo otro objeto sin tener que programar. Esto significa que la modificación de alguna parte del layout o del comportamiento común es tan fácil como modificarla en un único objeto y ¡listo!.

En una misma base de conocimiento se pueden definir tantas Master Pages como se desee.

Cuando estudiemos el objeto Web Panel comprenderemos que una Master Page será en particular un Web Panel categorizado como “Master Page” con todo lo que sea el Layout y comportamiento común a todas las páginas del sitio; dentro de este objeto se dejará un espacio para cargar en cada oportunidad la página que corresponda (el contenido variable del sitio). Eso se hará en el control presente en el form de nombre Content Placeholder.

Page 71: Aplicaciones Genexus

68

TransaccionesMaster Pages

• Propiedad Master Page

Las páginas web que implementan el contenido variable, se asocian a la Master Page, de manera que cada vez que se ejecuten, se carguen con ese “contexto” (el de la Master Page).

Page 72: Aplicaciones Genexus

69

Demo

• Agregar la transacción “Product” faltante y ver cómo se modifican los íconos en “Invoice”

¿Qué pasará al hacer F5?

Obsérvese cómo luego de crear la transacción “Product” GeneXus normaliza e indica gráficamente en la estructura de la transacción “Invoice” que los atributos, antes propios de la tabla INVOICEDETAIL, ahora serán inferidos, a través de la nueva clave foránea ProductId.

La clave primaria de la tabla INVOICEDETAIL seguirá siendo compuesta: {InvoiceId, ProductId}, pero además, el atributo ProductId sólo, será una FK a la tabla PRODUCT, a partir del cuál se inferirán los atributos ProductDescription y ProductPrice.

Luego del F5, naturalmente se informará de la necesidad de reorganizar la base de datos, creándose la tabla PRODUCT y modificándose la tabla INVOICEDETAIL de la manera que indicamos en los párrafos anteriores.

¿Qué pasará con los registros ya existentes en la tabla INVOICEDETAIL, para los que existían valores de ProductDescription y ProductPrice?Como se verá cuando se ejecute, el programa de reorganización agrega una rutina para crear los registros de productos en la tabla PRODUCT con esa información pre-existente. ¿Qué pasará si existía el mismo producto en varias líneas de distintas facturas?

Page 73: Aplicaciones Genexus

70

Integridad referencial

Page 74: Aplicaciones Genexus

71

CUSTOMER

COUNTRY

CustomerId*CustomerName

………CountryId

CountryId*CountryName

1

N

Integridad ReferencialDiagramas

El concepto de integridad referencial es un concepto que tiene que ver con las bases de datos relacionales.

Se refiere a que debe haber consistencia entre los datos de las distintas tablas de una base de datos relacional.

Las tablas de una base de datos relacional se encuentran relacionadas por atributos que tienen en común. Estas relaciones implican que los datos de las tablas no son independientes, sino que al insertar, modificar y eliminar registros en una tabla, se deben tener en cuenta los datos de las otras tablas para que siempre se conserve la consistencia de la información en la base de datos.

Si tenemos un modelo de datos relacional con las tablas:

COUNTRY (CountryId, CountryName)Clave Primaria: CountryId

CUSTOMER (CustomerId, CustomerName, CountryId, CustomerAddress, CustomerGender, CustomerStatus)

Clave Primaria: CustomerIdClave Foránea: CountryId (COUNTRY)

El hecho de que el atributo CountryId en la tabla CUSTOMER sea una clave foránea con respecto a la tabla COUNTRY, establece una relación entre ambas tablas. La relación entre ellas puede verse en el diagrama que mostramos arriba.

En dicho diagrama, la flecha simple representa la existencia de una instancia de la tabla apuntada, para cada instancia de la otra (es decir, que para cada cliente existe un y solo un país). La flecha doble representa la ocurrencia de varias instancias de la tabla apuntada, para cada instancia de la otra tabla (es decir, que para cada país, existen muchos clientes).

Se dice que la relación entre la tabla COUNTRY y la tabla CUSTOMER es 1 a N (1 a muchos).

Recíprocamente, la relación entre CUSTOMER y COUNTRY es N a 1 (muchos a 1).

Page 75: Aplicaciones Genexus

72

CUSTOMER

COUNTRY

1

N

En transacción “Customer”:• si se inserta nuevo registro, o • si se modifica el CountryId de un registro

Hay que verificar existencia del COUNTRY referenciado.

En transacción “Country”:• si se quiere eliminar un registro

Hay que verificar la no existencia de ningún CUSTOMER que lo referencie.

CUSTOMER

COUNTRY

1

N

Integridad ReferencialDiagramas

En la terminología GeneXus, decimos que existe una relación de subordinación entre ambas tablas. Decimos que:

COUNTRY está superordinada a CUSTOMERCUSTOMER está subordinada a COUNTRY

Significando que:

• Cuando se crea o modifica un registro en la tabla subordinada (CUSTOMER), debe existir el registro relacionado en la tabla superordinada (COUNTRY).

• Cuando se elimina un registro en la tabla superordinada (COUNTRY), no deben existir registros relacionados en la tabla subordinada (CUSTOMER).

Debido a esta relación entre las tablas, la información contenida en ellas no es independiente, y es necesario realizar controles para que los datos sean consistentes. A estos controles se les llama de Integridad Referencial y básicamente son los siguientes:

• Cuando se inserta o modifica un registro en la tabla CUSTOMER, el valor ingresado en el atributo que es clave foránea (CountryId), debe existir como valor de clave primaria de un registro en la tabla COUNTRY.

• Cuando se elimina un registro en la tabla COUNTRY, no deben existir registros en la tabla CUSTOMER cuyos valores de la clave foránea (CountryId), sean iguales al valor de la clave primaria del registro que se desea eliminar.

GeneXus genera los programas asociados a las transacciones, incluyendo en el código generado estos controles de Integridad Referencial. Por esta razón, si el usuario final inserta (o modifica) un cliente a través de la transacción "Customer", se validará automáticamente que el valor ingresado en el código de país CountryId, exista como clave primaria de un registro en la tabla COUNTRY. En caso de fallar este control de integridad referencial, un mensaje se le desplegará al usuario indicándole que no se encontró ese país.

Page 76: Aplicaciones Genexus

73

Integridad ReferencialIndices

Los índices son vías de acceso eficientes a las tablas.

GeneXus crea automáticamente algunos de ellos, y los otros deberán ser creados por el programador cuando éste así lo determine, basándose en criterios de optimización.

Existen cuatro tipos de índices en GeneXus:

• Primarios• Foráneos• De usuario•Temporales

De todos ellos, los únicos que no son creados automáticamente por GeneXus son los “de usuario”.

En cuanto a los tipos de índices que son creados por GeneXus, la diferencia que hay entre ellos es el momento en que son creados y el tiempo durante el cual se mantienen.

- Los índices primarios y foráneos son creados al momento de crear o reorganizar las tablas que componen la base de datos, y de ahí en más son mantenidos automáticamente por GeneXus.

- Los índices temporales, en cambio, son creados al ejecutar las aplicaciones, para acceder a tablas ordenadas por algún atributo o conjunto de atributos para el/los que no existe un índice de usuario creado; éstos se crean en tiempo de ejecución de las aplicaciones, se utilizan, y luego se eliminan.

ÍNDICES PRIMARIOS Y FORÁNEOS

GeneXus crea para cada tabla un índice por su clave primaria (índice primario), y un índice por cada clave foránea que la tabla tenga (índices foráneos). ¿Por qué crear índices primarios y foráneos para las tablas desde el comienzo en forma automática, siendo que luego deben ser mantenidos? Sean las tablas COUNTRY y CUSTOMER, que vimos un par de páginas atrás, creadas en nuestro modelo de datos a partir de las estructuras de las transacciones "Country" y "Customer”. Existe entre estas tablas una relación 1-N, que viene dada por el hecho de que el atributo CountryId en la tabla CUSTOMER es una clave foránea con respecto a la tabla COUNTRY.

Page 77: Aplicaciones Genexus

74

CustomerId*CustomerName

...CountryId

CountryId*CountryName

ICountryPK PK

FK

ICustomer

ICustomer1

1 Uruguay2 United States3 China

CountryId CountryName CustomerId CustomerName CountryId

4 Ann Silver 11 John Smith 13 Mary Jones 12 Jessica Deep 2

Si en transacción “Country”queremos eliminar “United States”:

El programa debe buscar sobre CUSTOMER si existe registro con CountryId = 2

para hacer eficiente esta búsqueda: índice foráneo (ICustomer1)

Integridad ReferencialIndices primarios y foráneos

Por existir esta relación, GeneXus incluye en los programas asociados a las transacciones "Country" y "Customer", los controles de integridad referencial pertinentes. Estos controles son:

• Si el usuario final inserta o modifica un cliente a través de la transacción "Customer", se validaráautomáticamente que el valor ingresado en la clave foránea CountryId exista como clave primaria de un registro en la tabla COUNTRY. En caso de fallar este control de integridad referencial, se le indicará al usuario que no se encontró ese país. Para controlar esto, se debe buscar en la tabla COUNTRY la existencia de un registro que tenga ese valor de CountryId como clave primaria; dado que se debe consultar la tabla COUNTRY, buscando por la clave primaria, resulta evidente que la búsqueda puede optimizarse si existe un índice por la clave primaria en dicha tabla.

• Si el usuario final intenta dar de baja un país a través de la transacción “Country”, se validaráautomáticamente que no existan clientes con dicho país asociado, como clave foránea; en caso de encontrar un registro en la tabla CUSTOMER, cuyo valor de clave foránea CountryId sea el que se desea eliminar, se le indicará al usuario que no es posible eliminar el país (ya que de lo contrario quedarían datos inconsistentes en la base de datos). Para controlar esto se debe consultar la tabla CUSTOMER, buscando por la clave foránea CountryId. Esta búsqueda será óptima si existe un índice por CountryId en la misma.

Control de unicidad de clave primariaOtro control que GeneXus también incluye en los programas asociados a las transacciones es la unicidad de la clave primaria; esto es, en ninguna tabla podrán existir dos registros con el mismo valor en la clave primaria.

Para controlar esto, cuando el usuario final intenta insertar un registro se valida automáticamente que el valor ingresado para la clave primaria no exista ya como clave primaria de otro registro en la tabla. Para hacer esta búsqueda con eficiencia, se debe utilizar el índice primario de la tabla.

Concluyendo, GeneXus al crear cada tabla de la base de datos crea también su índice primario, y un índice foráneo por cada clave foránea que la tabla contenga.

La creación de estos índices permite realizar los controles de integridad referencial y de unicidad de clave primaria accediendo a las tablas de forma eficiente.

Page 78: Aplicaciones Genexus

75

• Los crea el analista sobre una tabla. Deberá categorizarlos según si aceptará valores repetidos (duplicate) o no (unique).

• Si en la realidad modelada, un mismo nombre se puede repetir para dos clientes:

CustomerId CustomerName CountryId

1 Ann 12 Ann 23 Mary 1

Integridad ReferencialIndices de Usuario

Índices de usuario

Estos índices deben ser definidos explícitamente por el analista. No son definidos automáticamente. Se dividen en duplicate y unique.

Un índice de usuario duplicate es aquel que se define para atributos de una tabla para los quepueden existir varios registros con el mismo valor en los mismos (es decir, se define para atributos que no son una clave candidata). Este tipo de índices se define fundamentalmente para acceder a los datos ordenados por determinados atributos de forma eficiente. A modo de ejemplo, suponiendo que el nombre de cliente no es clave en la tabla CUSTOMER (sus valores se pueden repetir) podremos definir un índice de usuario duplicate por el atributo CustomerName, siendo muy útil para realizar consultas y listados que se necesite salgan ordenados por nombre.

Un índice de usuario unique se utiliza para especificar que un conjunto de atributos es clave candidata en una tabla (diferente de la clave primaria). Esta es la forma de representar claves candidatas en el modelo de datos. Con ello logramos que GeneXus incorpore automáticamente el control de unicidad correspondiente en las transacciones asociadas. A modo de ejemplo, si el nombre de cliente no se puede repetir, la forma de representarlo y lograr que GeneXus lo controle automáticamente es definiendo en la tabla CUSTOMER un índice de usuario unique por el atributo CustomerName.

Page 79: Aplicaciones Genexus

76

• Si un mismo nombre no puede repetirse (es por tanto un atributo clave de la tabla)

• La forma de definir claves candidatas en el modelo de datos es através de índices unique. GeneXus pasará a incorporar controles en las transacciones, utilizando el índice, para no permitir la inserción de registros duplicados.

CustomerId CustomerName CountryId

1 John Smith 12 Ann Jones 23 Richard Land 1

Si se intenta ingresar un nuevo cliente con nombre “Ann Jones”la transacción dará un error de registro duplicado.

Integridad ReferencialIndices de Usuario

Índices unique (claves candidatas)

En una tabla de la base de datos pueden existir varios conjuntos de atributos cuyos valores sean únicos en la realidad. Se dice que cada uno de esos conjuntos es una clave de la tabla. Luego, el analista elige una de las claves como la clave primaria. GeneXus identifica la clave primaria de la tabla de acuerdo a los atributos que fueron calificados por el analista con el símbolo de llave.

Supongamos que en la realidad además de poder identificar a un cliente por su código, también se lo puede identificar por su cédula de identidad. En este caso tanto el atributo CustomerId como el atributo CustomerSSN (donde se almacena la cédula de identidad) serían claves de la tabla CUSTOMER. Al indicar que CustomerId es el identificador de la transacción, GeneXus crearáautomáticamente un índice primario por dicho atributo y controlará la unicidad de los valores ingresados para el mismo.

¿Y qué sucederá con la cédula de identidad del cliente? Al ser este atributo clave, quisiéramos que GeneXus obrara de igual manera, no permitiendo que se ingrese un registro, si es que ya existe otro con el mismo valor de cédula de identidad (CustomerSSN). Para poder controlar esto de forma eficiente, GeneXus debería contar con un índice por cada atributo clave.

La forma de definir en GeneXus que un atributo o conjunto de atributos es clave alternativa o candidata y que por lo tanto se debe chequear su unicidad, es definiendo un índice de usuariocompuesto por ese atributo o conjunto de atributos, y calificándolo de “unique” en lugar de “duplicate”, que es el valor por defecto de un índice de usuario.

A partir de allí, GeneXus incluirá en la lógica de la transacción ese control de unicidad utilizando ese índice definido por el usuario.

En resumen, las transacciones GeneXus realizan automáticamente los siguientes controles:• Integridad referencial• Unicidad de clave (tanto primaria como candidatas)

Page 80: Aplicaciones Genexus

77

• Son creados automáticamente, bajo ciertas condiciones, cuando son necesarios, y se eliminan cuando termina la ejecución del objeto que los creó.

• Si se desea acceder a los datos ordenados por determinados atributos, pero no se desea crear un índice permanente para ello: GeneXus creará un índice temporal.

• En algunas plataformas, las consultas para las cuales se quiere obtener el resultado ordenado por determinados atributos, y no existe el índice de usuario, son resueltas por el DBMS correspondiente sin la creación de índices temporales.

• El usuario puede resolver dejar de utilizar un índice temporal, creando un índice de usuario.

Integridad ReferencialIndices Temporales

Índices temporales

Si se desea acceder a los datos ordenados por determinados atributos, pero no se desea crear un índice permanente para ello (por ejemplo, porque se trata de una consulta que se realiza con muy poca frecuencia), entonces, dependiendo de la plataforma, se creará un índice temporal.

Page 81: Aplicaciones Genexus

78

• Para cada atributo no inferido, ni identificador en la estructura de una transacción, es posible definir si admitirá nulos o no, en la tabla asociada.

Integridad ReferencialManejo de nulos

La permisión o no del valor <NULL> en la base de datos es muy importante en el modelo relacional. Permitir el “valor” null para un atributo dado, significa que puede, bajo ciertas circunstancias, ser “ignorado” dado que es “valor no especificado”. Por otro lado, si un atributo no permite valor null, un valor válido siempre deberá asignarse a él.

La propiedad Nulls (presentada como columna en el editor de estructuras de transacciones), permite configurar para cada atributo si admite o no valor null en la tabla asociada. Los atributos para los cuales puede configurarse esto, es para aquellos almacenados en la(s) tabla(s) asociada(s) a la transacción (es decir, no inferidos) siempre y cuando no sean atributos primarios en dichas tablas (ya que por definición las claves primarias no soportan valor null).

Resumiendo: el objetivo de esta propiedad es definir qué valor se va a almacenar en la base de datos cuando no digitemos nada en el campo (el valor <NULL> o el valor empty).

Page 82: Aplicaciones Genexus

79

• Valores posibles que ofrece la propiedad Nulls:- No: Valor por defecto. El atributo en la tabla asociada, no

permitirá valor null - Yes: el atributo en la tabla asociada, sí admitirá valor null

• Atributos parte de la clave primaria no soportan valor null (propiedad Nulls = No, siempre)

• Atributos clave foránea sí, y esto tendrá repercusión en los controles de integridad referencial.

Integridad ReferencialManejo de nulos

Los valores posibles de configurar para la propiedad Nulls son:

No: significa que el atributo no permitirá el valor null en la tabla asociada (valor por defecto) Yes: significa que el atributo sí admitirá el valor null en la tabla asociada

La definición de nulls es utilizada por GeneXus al momento de crear / reorganizar las tablas de la base de datos, ya que el soporte o no soporte de nulabilidad de los atributos en su tabla, se define a nivel de la base de datos.

O sea que modificar el valor de la propiedad Nulls para un atributo implicará ejecutar una reorganización (para redefinir a nivel de la base de datos el soporte de nulabilidad del atributo en su tabla).

Page 83: Aplicaciones Genexus

80

• Repercusión en controles de integridad referencial

1) CountryId y CityId con propiedad Nulls=No

• Se realizan los chequeos de IR mostrados arriba

2) CityId con propiedad Nulls=Yes

• Se agrega un control de IR en CUSTOMER si se deja nulo CityId, se realizará chequeo contra COUNTRY.

CountryId*CountryName

CountryId*CityId*CityName

CustomerId*CustomerNameCountryIdCityId

FK compuesta

Integridad ReferencialManejo de nulos

Repercusión en controles de integridad referencial

La definición de nulls para atributos que conforman una clave foránea le dice a GeneXus cuán fuerte es la referencia a la otra tabla.

Si ninguno de los atributos que componen una clave foránea permiten valores nulos (caso 1), se tratará de una referencia fuerte (también conocida como “not null reference”), ya que establece que la FK deberá siempre apuntar a un registro existente de la tabla referenciada.

Por el contrario, una clave foránea que tenga al menos un atributo que soporte nulos (caso 2), establece una referencia débil (también conocida como “null reference”), ya que si alguno de los atributos que conforman la clave foránea son nulls, entonces la referencia no será chequeada.

Cuando una clave foránea es compuesta y están permitidos los nulos para algunos de sus atributos, pueden aparecer nuevas referencias (no chequeadas en caso de tratarse de referencias fuertes) si los atributos que restan componen también una clave foránea. Un ejemplo es el que presentamos arriba, donde en caso de que el usuario deje nulo el valor de CityId para un cliente, se realizará el chequeo de IR contra COUNTRY, para asegurarse que el país ingresado sea correcto.

Page 84: Aplicaciones Genexus

81

• Diferencia entre valor empty y null para atributos:

• empty: es un valor (0 para Numeric, “” para Character, etc.)

• null: si está permitido, no es un valor. Significa que el valor debe ser considerado como:

• no especificado• no disponible• no asignado• desconocido

• Métodos según si atributo permite null o empty:

• IsEmpty• IsNull• SetEmpty• SetNull

Integridad ReferencialManejo de nulos

Métodos para trabajar con nulos y vacíos

IsEmpty, IsNull: devuelven true en caso de que el atributo contenga valor empty o null respectivamente.

SetEmpty, SetNull: configuran en el atributo el valor empty o null, respectivamente.

Ejemplos:

* error(‘You must specify a name’) if CustomerName.IsEmpty();

* msg(‘Warning: You didn’t specify a Country’) if ContryId.IsNull();

Page 85: Aplicaciones Genexus

82

Tabla basey

Tabla extendida

Page 86: Aplicaciones Genexus

83

Los criterios de normalización del diseño de la base de datos apuntan a minimizar la posibilidad de inconsistencia en los datos. Una base de datos diseñada de esta manera tiene una serie de ventajas importantes (tal es así que actualmente la normalización de datos es un estándar de diseño), pero se deben tener en cuenta también algunos inconvenientes.

El inconveniente más notorio es que los datos se encuentran dispersos en muchas tablas, y por lo tanto cuando se quieren hacer consultas más o menos complejas a la base de datos, se debe consultar una cantidad importante de tablas.

Así, por ejemplo, si el siguiente diagrama representa nuestro modelo de datos:

para listar las facturas sería necesario consultar las tablas: INVOICE e INVOICEDETAIL (líneas de Facturas), CUSTOMER, COUNTRY y PRODUCT.

Para simplificar esta tarea GeneXus utiliza el concepto de tabla extendida.

Llamamos tabla base a cualquier tabla de la base de datos en la cual estemos posicionados en determinado momento; y dada cierta tabla base, su tabla extendida comprenderá a todos los atributos de la propia tabla base, más todos los atributos de las tablas que tengan información relacionada unívocamente con la tabla base (relación N-1 desde la tabla base, directa e indirectamente).

Page 87: Aplicaciones Genexus

84

INVOICE CUSTOMER COUNTRY

INVOICEDETAIL PRODUCT

InvoiceId*InvoiceDateCustomerId

CustomerId*CustomerNameCountryIdCustomerGenderCustomerStatus

CountryId*CountryName

InvoiceId*ProductId* InvoiceDetailQuantityInvoiceDetailAmount

ProductId*ProductDescriptionProductPriceProductStock

Tabla Base y Tabla Extendida

Utilizando el diagrama es fácil determinar cuál es la tabla extendida correspondiente a una tabla base cualquiera:

Partiendo de la tabla base, se deben seguir las relaciones N-1, (es decir, se deben seguir las flechas que tienen punta doble partiendo desde la tabla base, y punta simple en el otro extremo).

Todas las tablas a las cuales se pueda llegar siguiendo las flechas que representan relaciones N-1 desde la tabla base, formarán parte de su tabla extendida.

El siguiente cuadro muestra la tabla extendida correspondiente a cada una de las tablas de nuestro modelo de datos:

Page 88: Aplicaciones Genexus

85

• Se utilizan para definir el comportamiento de las transacciones.• Algunas reglas:

• Pueden incluir: atributos, variables, constantes y funciones.• Son LOCALES a la transacción.• Programación DECLARATIVA.

DefaultAsignaciónMsgErrorNoacceptAddSubtractSerialUpdate

Reglas

Las reglas, en el objeto transacción, cumplen un rol muy importante ya que permiten programar su comportamiento (por ejemplo: asignar valores por defecto, definir controles sobre los datos, etc.).

Se escriben de forma declarativa, es decir que el orden en el que se escriben no significa que sea el orden en el que se ejecutarán.

Pueden involucrar a los atributos definidos en la estructura de la transacción1, así como a variables definidas dentro del objeto, constantes y funciones.

Son solo válidas dentro de la transacción en la que están definidas, es decir, son locales.

--------------------------------------------------------------------------------------------------------1 Todas las reglas de transacciones pueden involucrar atributos de las tablas base asociadas a la transacción; y la mayor parte de ellas puede también involucrar atributos de las tablas extendidas de dichas tablas base. Para poder referenciar un atributo en una regla, el mismo deberá estar incluido en la estructura de la transacción (ya sea que pertenezca a alguna de las tablas base asociadas a la transacción, o a sus tablas extendidas).

Page 89: Aplicaciones Genexus

86

Algunas reglas válidas para transacciones son:

Default

OBJETIVO: Permite asignar un valor por defecto a un atributo o variable; el valor por defecto inicializará al atributo o variable si se está realizando una inserción por medio de la transacción (modo Insert), pero el usuario final podrácambiarlo si ese valor no es el que desea.

SINTAXIS: Default( att | &var, exp );

DONDE:• att: es un atributo perteneciente a alguna de las tablas base asociadas a la transacción. • var: es el nombre de una variable.• exp: es una expresión que puede involucrar constantes, funciones, variables u otros atributos.

FUNCIONALIDAD: Esta regla asigna el valor de la expresión exp como valor por defecto del atributo att o variable var,cuando la transacción se ejecuta en modo Insert.

Esta regla no es válida para atributos que forman parte de la clave primaria de alguno de los niveles de la transacción, porque es disparada luego de que la clave es ingresada (ya que solo en ese momento el modo es conocido y esta regla se dispara solo en modo Insert).

EJEMPLOS: Default( InvoiceDate, &today ); /*Regla definida en la transacción “Invoice”*/

Cuando se está insertando una factura nueva, se sugiere como valor de InvoiceDate el valor contenido en la variable del sistema today.

Default( InvoiceDate, Today()); /*Regla definida en la transacción “Invoice”*/

Análoga a la anterior, solo que en lugar de utilizar la variable del sistema today, se utiliza la función Today que devuelve la fecha correspondiente al día.

Default( InvoiceDetailAmount, ProductPrice*InvoiceDetailQuantity); /* Regla definida en “Invoice” */

Cuando se está insertando una línea de factura, se sugiere que el atributo InvoiceDetailAmount (importe de la línea) tome el valor resultante de evaluar la expresión ProductPrice*InvoiceDetailQuantity (precio del producto por cantidad llevada del mismo).

Nota: El tipo de datos de la expresión debe coincidir con el tipo de datos del atributo o variable

Regla de asignación

OBJETIVO: Permite asignar a un atributo o a una variable, el valor de una expresión.

SINTAXIS: att | &var = exp [if cond] [on evento/momento de disparo];

DONDE: • att: es un atributo perteneciente a alguna de las tablas base asociadas a la transacción, o a sus tablas extendidas (debe estar declarado en la estructura).• var: es el nombre de una variable.• exp: es una expresión que puede involucrar constantes, funciones, variables u otros atributos, y debe ser del mismo tipo que att o var.• cond: es una expresión booleana (puede contener los operadores lógicos and, or, not)• evento/momento de disparo: es uno de los eventos predefinidos de GeneXus disponibles para reglas de transacciones, que permiten definir el momento específico de ejecución de una regla.

FUNCIONALIDAD: Una regla de este tipo permite asignar al atributo o variable de la izquierda, el valor resultante de evaluar la expresión. Como puede verse, la condición es opcional; de no ponerla, la asignación se realiza siempre.

La asignación a un atributo, implica su actualización en el registro que corresponda. Se pueden definir reglas de asignación a atributos de alguna de las tablas bases asociadas a la transacción, e incluso de sus tablas extendidas. Esto significa que pueden actualizarse atributos inferidos en una transacción (siendo necesario declararlos en la estructura).

Page 90: Aplicaciones Genexus

87

EJEMPLO:

InvoiceDetailAmount = ProductPrice*InvoiceDetailQuantity; /*Regla definida en la transacción “Invoice”*/

Si el importe de cada línea de una factura se calcula siempre multiplicando el precio del producto por la cantidad llevada del mismo, podemos utilizar esta regla de asignación para liberar al usuario de realizar el cálculo.

Error

OBJETIVO: Permite desplegar un mensaje de error si la condición se satisface. Sirve para definir los controles que deben cumplir los datos.

SINTAXIS: Error( ‘msg’ | &var | character expresion, msgId ) if cond [on evento/momento de disparo];

DONDE:• msg: es un string con un mensaje de error a desplegar.• var: es el nombre de una variable de tipo character, que contiene un string con un mensaje de error a desplegar.• character expression: es una expresión cuyo tipo resultante es character y que será desplegada.• msgId: es un string (sin espacios en blanco ni comillas) que será utilizado solo si la transacción es definida también como business component1.• cond: es una expresión booleana (que puede contener los operadores lógicos and, or, not)• evento/momento de disparo: es uno de los eventos predefinidos de GeneXus disponibles para reglas de transacciones, que permiten definir el momento específico de ejecución de una regla.

FUNCIONALIDAD: Esta regla despliega el mensaje del parámetro msg, var o character expresion, si la condición cond que se evalúa resulta verdadera. El mensaje de error se despliega en una ventana popup cuando el ambiente de trabajo es Windows y en el control Error Viewer y/o un cuadro de texto cuando el ambiente de trabajo es Web, deteniendo cualquier actualización a la base de datos. Cuando la transacción se ejecuta como business component (estudiaremos este tema mas adelante en el curso), de dispararse el error, generará una entrada en el SDT messages, con identificador msgId.

EJEMPLOS:

Error(‘No se permiten clientes sin nombre’) if CustomerName.isEmpty();/*Regla definida en la transacción “Customer”*/

Se evalúa la condición CustomerName.isEmpty(), y si ésta se satisface, se despliega el mensaje ‘No se permiten clientes sin nombre’ en pantalla. No se permite continuar hasta que el usuario ingrese un nombre en el campo CustomerName o abandone la transacción (en cuyo caso no se hará en la base de datos actualización alguna).

Error(‘No se permite eliminar facturas’) if Delete;/* Regla definida en la transacción “Invoice” */

Se necesita prohibir la eliminación de facturas. Con esta regla, si el usuario intenta realizar una eliminación, la condición dará True y se disparará la regla, evitando la eliminación.

Msg

OBJETIVO: Permite desplegar un mensaje de advertencia si la condición se satisface.

SINTAXIS: Msg( ‘msg’ | &var | character expresion, msgId) if cond [on evento/momento de disparo];

DONDE:msg, var, character expresion, msgId, cond, evento/momento de disparo: son los mismos que para la regla error.Observar que la sintaxis es exactamente la misma.

FUNCIONALIDAD: Esta regla se utiliza para presentar mensajes de advertencia al usuario. Despliega el mensaje del primer parámetro, si la condición se satisface, análogamente a la regla Error; pero a diferencia de esta última, permite continuar con la ejecución si la condición sigue satisfaciéndose. Del mismo modo, si la transacción es business component1, de dispararse la regla genera entrada en el SDT messages.

Los mensajes de advertencia se despliegan en el Error Viewer.

Page 91: Aplicaciones Genexus

88

EJEMPLO:

Msg( ‘No se permiten clientes sin nombre’ ) if CustomerName.isEmpty();/*Regla definida en la transacción “Customer”*/

Se evalúa la condición CustomerName.isEmpty(), y si ésta se satisface se despliega el mensaje ‘No se permiten clientes sin nombre’. A diferencia de lo que ocurre con la regla Error, aquí sí se permite continuar la ejecución, pues no se trata de un error sino de una advertencia.

Noaccept

OBJETIVO: Permite indicar que los atributos no aceptarán valores por parte del usuario (serán solo de salida).

SINTAXIS: Noaccept( att1[, atti]…) [if cond];

DONDE:atti: es un atributo perteneciente a alguna de las tablas bases asociadas a la transacción.cond: es una expresión booleana (puede contener los operadores lógicos and, or, not).evento/momento de disparo: es uno de los eventos predefinidos de GeneXus disponibles para reglas de transacciones, que permiten definir el momento específico de ejecución de una regla.

FUNCIONALIDAD: En una transacción, todos los atributos que pertenecen a las tablas base asociadas a la transacción, por defecto son aceptados. Si queremos que algunos atributos con estas características no sean aceptados, entonces contamos con la regla Noaccept.

EJEMPLO:Noaccept( IvoiceDate) if Update; /* Regla definida en la transacción “Invoice” */

Si se está modificando una factura (modo Update), no se permite que se modifique su fecha.

Subtract

OBJETIVO: Sustrae el valor de un atributo al valor de otro atributo, si se satisface la condición especificada.

SINTAXIS: subtract(att1, att2) [if cond];

DONDE:att1, att2: son atributos pertenecientes a alguna de las tablas base asociadas a la transacción, o a sus tablas extendidas (y deben estar declarados en la estructura)cond: es una expresión booleana (que puede contener los operadores lógicos and, or, not).

FUNCIONALIDAD: La sustracción se realiza teniendo en cuenta el modo en el que se esté trabajando en la transacción (Insert, Update o Delete). En modo:

- Insert: se le sustrae al valor del atributo att2, el valor del atributo att1- Delete: se le suma al valor de att2, el valor del atributo att1- Update: se le sustrae al valor del atributo att2, la diferencia entre el valor nuevo y el viejo de att1

EJEMPLO:

En la transacción “Invoice”, cada vez que se ingresa una línea con un producto que se está comprando, se debe disminuir el stock del mismo, según la cantidad llevada.

Esto podría hacerse en forma sencilla con la siguiente regla de asignación:

ProductStock = ProductStock – InvoiceDetailQuantity;

Si prestamos atención, sin embargo, vemos que esta regla no nos sirve, pues no está condicionada a un modo particular, razón por la cuál se disparará tanto cuando se está insertando una nueva línea en la factura, como cuando se estáeliminando o modificando una ya existente. Y en estos últimos dos casos es incorrecto disparar la regla.

Page 92: Aplicaciones Genexus

89

De hecho, cuando se esté eliminado una línea existente, debe realizarse la operación contraria, es decir, se debe “devolver”al stock lo que se había quitado cuando se insertó la línea.

Lo correcto entonces, teniendo en cuenta todos los casos posibles sería tener 3 reglas:

ProductStock = ProductStock – InvoiceDetailQuantity if Insert;ProductStock = ProductStock + InvoiceDetailQuantity if Delete;ProductStock = ProductStock + old(InvoiceDetailQuantity) – InvoiceDetailQuantity if Update;

Aquí estamos utilizando la función “old”, que devuelve el valor almacenado del atributo (es el valor antes de modificarlo). Para evitar tener que hacer todo esto, GeneXus provee la regla subtract que se encarga de hacer la asignación correcta de acuerdo al modo. Entonces podemos sustituir las 3 asignaciones anteriores, por:

subtract( InvoiceDetailQuantity, ProductStock);

Esta regla tiene la inteligencia para, dependiendo del modo, restar o sumar.

Add

OBJETIVO: Suma el valor de un atributo al valor de otro atributo, si se satisface la condición especificada

SINTAXIS: add( att1, att2) [if cond];

DONDE:att1, att2: son atributos pertenecientes a alguna de las tablas base asociadas a la transacción, o a sus tablas extendidas (y deben estar declarados en la estructura).cond: es una expresión booleana.

FUNCIONALIDAD: La adición se realiza teniendo en cuenta el modo en el que se esté trabajando en la transacción (Insert, Update o Delete).

En modo:- Insert: se le suma al valor del atributo att2, el valor del atributo att1- Delete: se le sustrae al valor de att2, el valor del atributo att1- Update: se le suma al valor del atributo att2, la diferencia entre el valor nuevo y el viejo de att1

EJEMPLO:Definimos en la transacción “Customer”, un atributo de nombre CustomerTotalPurchases, para registrar el importe total de compras efectuadas por el mismo. El comportamiento que se desea es que cada vez que se cree una factura para un cliente dado, se le sume el total de la factura (InvoiceAmount) al total de compras efectuadas por el cliente (CustomerTotalPurchases).

Al igual que vimos en la regla subtract, no debemos olvidar que en la transacción “Invoice” podemos también eliminar y modificar facturas, y no solo crearlas; por lo tanto es importante tener en cuenta el modo de trabajo en la transacción (Insert, Update, Delete). GeneXus nos libera de tener que considerar nosotros a los modos, teniendo que escribir las siguientes tres reglas de asignación en la transacción “Invoice”:

CustomerTotalPurchases = CustomerTotalPurchases + InvoiceAmount if Insert;CustomerTotalPurchases = CustomerTotalPurchases – InvoiceAmount if Delete;CustomerTotalPurchases = CustomerTotalPurchases – old(InvoiceAmount) + InvoiceAmount if Update;

y en su lugar nos provee de la regla add, que se encarga de sumar o restar, dependiendo del modo.

Page 93: Aplicaciones Genexus

90

Así es que si en la transacción “Customer” agregamos el atributo CustomerTotalPurchases (total de compras del cliente):

CustomerId*CustomerNameCustomerAddressCustomerGender...CustomerTotalPurchases

y en la transacción “Invoice” inferimos al atributo CustomerTotalPurchases, ya que pertenece a la tabla extendida y podemos definir la regla:

add( InvoiceAmount, CustomerTotalPurchases );

y logramos el comportamiento deseado, que es:

• si se inserta una factura (Insert): se le suma al valor del atributo CustomerTotalPurchases el valor del atributo InvoiceAmount• si se elimina una factura (Delete): se le sustrae al valor del atributo CustomerTotalPurchases el valor del atributo InvoiceAmount• si se modifica una factura (Update): se le suma al valor del atributo CustomerTotalPurchases, la diferencia entre el valor nuevo y el viejo de InvoiceAmount

Serial

OBJETIVO: Permite numerar serialmente atributos numéricos.

SINTAXIS: Serial( att1, att2, step);

DONDE:• att1: es un atributo perteneciente a alguna de las tablas base asociadas a la transacción (es decir, no inferido), que desea autonumerarse (debiendo estar declarado en la estructura). • att2: Tiene que pertenecer a una tabla directamente superordinada a la del atributo att1.• step: es el paso o incremento de la serialización.

FUNCIONALIDAD: El propósito de esta regla es asignar un número correlativo a att1 cada vez que se inserta un registro en la tabla a la que pertenece att1. Se toma el valor de att2 (att2 contiene el último número utilizado en la autonumeración), se le suma el valor del parámetro step, y el valor resultante se asigna tanto al atributo att1 del nuevo registro, como al atributo att2 para conservar el último número asignado.

Es decir, cuando se está insertando un registro por medio de una transacción en la cual se ha definido la regla: Serial(att1, att2, step);, se accede al att2 (habrá un solo valor de este atributo relacionado, pues pertenece a una tabla directamente superordinada1), se le suma el valor step, y se asigna el valor obtenido tanto a att1 del registro que va a ser insertado, como a att2 perteneciente a una tabla directamente superordinada con respecto a la tabla que contiene a att1.

Si se diseña a la transacción “Invoice” conteniendo un Número de Línea de Factura (atributo InvoiceDetailId)como identificador único del segundo nivel, la estructura de la transacción sería:

Invoice{

InvoiceId*CustomerIdCustomerNameInvoiceDateInvoiceLastLineId

Detail{

InvoiceDetailId*ProductIdProductDescription……

}}

Page 94: Aplicaciones Genexus

91

En este diseño el atributo ProductId no es identificador único del nivel, sino clave foránea únicamente.

Cada línea tiene un número de línea que la identifica en forma única, y es posible ingresar el mismo producto en distintas líneas.

Podría ser útil asignar por medio del sistema, números correlativos al campo InvoiceDetailId, definiendo la regla:

serial(InvoiceDetailId, InvoiceLastLineId, 1);

El primer parámetro de la regla serial define cuál es el atributo a numerar automáticamente, en el segundo parámetro debe indicarse un atributo cuya función es guardar el último valor asignado hasta el momento, y por último el tercer parámetro es para indicar el incremento (en este caso se incrementa de uno en uno).

El segundo parámetro (en el ejemplo InvoiceLastLineId) debe pertenecer a una tabla directamente superordinada a la tabla que contiene el atributo que se desea numerar automáticamente (InvoiceDetailId). La regla serial lo requiere así. En el ejemplo, se puede observar que InvoiceLastLineId se encuentra en la tabla de clave InvoiceId*, la cual es directamente superordinada respecto a la tabla que contiene el atributo a numerar (InvoiceDetailId).

Es decir, cada factura tendrá en el cabezal un atributo que almacenará el último número de línea asignado hasta el momento (InvoiceLastLineId). La regla serial está implementada de forma tal que necesita este atributo (para fijarse el último número utilizado, sumarle el incremento, y asignar el próximo número a la nueva línea).

Consideración:La regla serial es útil a la hora de autonumerar líneas, no así cabezales (por ejemplo identificadores de facturas, de clientes, etc.). El motivo es el siguiente: para utilizar la regla serial, se requiere definir un atributo en una tabla directamente superordinada; esto resulta bien sencillo si se desean autonumerar líneas ya que alcanza con incluir este atributo en el nivel de la estructura inmediatamente superior al del atributo a autonumerar.

Page 95: Aplicaciones Genexus

92

Sin embargo, contamos con una solución mucho más simple para autonumerar cabezales: cuando una tabla tiene una clave simple (es decir formada por un solo atributo) y el tipo de datos es numérico, puede numerarse automáticamente utilizando la funcionalidad que brindan los manejadores de base de datos para esto. La forma de indicarlo en GeneXus es configurando la propiedad Autonumber del atributo clave:

Si en la propiedad Autonumber de un atributo numérico clave, se selecciona el valor True, significa que se realizará la numeración automática del mismo. Se agregarán las siguientes propiedades en el diálogo:

Start: Mediante esta propiedad se configura a partir de qué número comienza la numeración automática.

Step: Mediante esta propiedad es posible configurar el incremento del campo (entre dos registros).

For replication: Esta propiedad es sólo válida para el motor de base de datos SQL Server; el valor Yes le indica a éste que no debe aplicar la propiedad en caso de que la tabla sea receptora de replicación (sino que debe mantener los números que le vienen por replicación).

Para profundizar en el manejo de esta propiedad, recomendamos acceder al Help de GeneXus.

Page 96: Aplicaciones Genexus

93

Update

OBJETIVO: Posibilita actualizar en el form de una transacción (win/web) atributos de la tabla extendida (inferidos).

SINTAXIS: Update( att1[, atti …]);

DONDE:atti: es un atributo perteneciente a la tabla extendida de alguna de las tablas bases asociadas a la transacción.

FUNCIONALIDAD: En una transacción, todos los atributos que pertenecen a las tablas base asociadas a la transacción, por defecto son aceptados y los que perteneciendo a la tabla extendida, no pertenecen a la base, son inferidos, y por tanto no aceptados. Pero si queremos que algunos de estos atributos inferidos sean aceptados, para que el usuario pueda modificar desde el form su valor, entonces contamos con la regla Update.

EJEMPLO:

InvoiceId*InvoiceDateCustomerIdCustomerName…

CustomerId*CustomerName…

update(CustomerName);

Page 97: Aplicaciones Genexus

94

• ¿En qué nivel de una transacción se ejecutarán las reglas definidas en la misma?

• ¿Cómo condicionar reglas para que se ejecuten en determinados modos?

ReglasConceptos importantes

¿En qué nivel de una transacción se ejecutarán las reglas definidas en la misma?

La mayor parte de las veces no es necesario agregar explícitamente en la definición de las reglas el nivel de la transacción en el cual se desea que se disparen, ya que los atributos involucrados en las reglas le dan la pauta a GeneXus del nivel en el cual corresponde ejecutarlas.Por ejemplo, si una regla referencia únicamente a atributos del primer nivel de la transacción en la cual se encuentra definida (ya sea en la propia regla o en la condición de disparo), GeneXus entenderá que la misma estará asociada al primer nivel de la transacción. Análogamente, si una regla referencia solamente a atributos del segundo nivel de la transacción en la cual se encuentra definida (ya sea en la propia regla o en la condición de disparo), GeneXus entenderá que la misma estará asociada al segundo nivel de la transacción.

En el caso que una regla referencie atributos de varios niveles, GeneXus entenderá que la regla estaráasociada al último de los niveles de los atributos involucrados, ya que será en el último nivel en el que contará con los valores de todos los atributos implicados.

A continuación presentamos ejemplos concretos:

1) Si se define la siguiente regla en la transacción “Invoice”:Default(InvoiceDate, &today);

como el único atributo que se menciona en la regla es InvoiceDate, y es un atributo del primer nivel de la transacción, GeneXus determinará que se tratará de una regla asociada al primer nivel.

2) Si se define la siguiente regla en la transacción “Invoice”:subtract( InvoiceDetailQuantity, ProductStock );

como los dos atributos que se mencionan en la misma se encuentran en el segundo nivel de la transacción, GeneXus determinará que se tratará de una regla asociada al segundo nivel.

Page 98: Aplicaciones Genexus

95

3) Si se define la siguiente regla en la transacción “Invoice”: InvoiceDetailDiscount= InvoiceDetailAmount * CustomerDiscountPercentage/100;

siendo InvoiceDetailDiscount (descuento correspondiente a una línea) un atributo perteneciente al segundo nivel de la transacción “Invoice” y CustomerDiscountPercentage (porcentaje de descuento otorgado a un cliente) un atributo declarado en el primer nivel de la transacción “Invoice”, GeneXus determinará que se tratará de una regla asociadaal segundo nivel de la transacción.

Cuando nos referimos a que una regla está asociada a determinado nivel, significa que la misma se ejecutará para cada instancia con la cual se trabaje a través de ese nivel (si se cumple la condición de disparo de la regla, claro está).

En el caso del primer ejemplo visto, la regla Default(InvoiceDate, &today) es una regla asociada al primer nivel de la transacción “Invoice”. Esto significa que se ejecutará para todo cabezal de factura que se inserte a través del primer nivel de la transacción “Invoice” (la regla Default tiene la particularidad de dispararse únicamente cuando el modo de ejecución es Insert).

En el caso del segundo ejemplo visto, la regla Subtract(InvoiceDetailQuantity, ProductStock) es una regla asociadaal segundo nivel de la transacción “Invoice”. Esto significa que se ejecutará para toda línea de factura que se inserte, actualice o elimine a través del segundo nivel de la transacción “Invoice”.

En el caso del tercer ejemplo, la regla:InvoiceDetailDiscount = InvoiceDetailAmount * CustomerDiscountPercentage/100 es una regla asociada al segundo nivel de la transacción “Invoice”. De modo que esta regla se ejecutará para toda línea de factura que se inserte, actualice o elimine a través del segundo nivel de la transacción “Invoice”.

Concluyendo, tal como se desprende de todo lo explicado, para cada factura con la cual se trabaje a través de la transacción “Invoice”:- para el cabezal: se ejecutarán las reglas asociadas al primer nivel - para cada una de las líneas: se ejecutarán las reglas asociadas al segundo nivel

Es importante saber que como norma general GeneXus siempre determina que una regla se dispare en el primer momento en que sea posible, es decir, en aquel momento en el que cuente con todos los datos necesarios. Y solamente en algunos casos que así lo requieran, una misma regla se volverá a disparar más adelante.

¿Qué nivel de disparo por defecto se le asociará a una regla que no referencia atributos?

Cuando no hay atributos involucrados en una regla, el nivel asociado por defecto a la regla será el primero.

Por ejemplo, la siguiente regla definida en la transacción “Invoice”:Error(‘No se permite eliminar facturas’) if Delete;

no tiene atributos involucrados, por lo tanto, el nivel asociado por defecto a la regla será el primero.

¿Cuándo hay que especificar explícitamente el nivel de disparo de una regla?

Existe una cláusula opcional de nombre Level que permite modificar el nivel por defecto de disparo de una regla, cambiándolo por un nivel posterior.

Es decir, si por ejemplo una regla se ejecuta por defecto para el primer nivel de una transacción y se desea que se ejecute para el segundo, se deberá agregar a la regla el componente Level seguido de un atributo o conjunto de atributos del segundo nivel. Esto hará que la regla se ejecute para cada una de las instancias correspondientes a las líneas, y no para la instancia correspondiente al cabezal como era el comportamiento por defecto.

Por ejemplo, si definimos la siguiente regla en la transacción “Invoice”:Msg(‘La fecha de la factura es mayor a la fecha actual’) if InvoiceDate > &Today;

por defecto esta regla estará asociada al primer nivel de la transacción, ya que el único atributo referenciado en la regla se encuentra en el primer nivel de la transacción. Si por algún motivo deseamos que la regla se ejecute para cada una de las instancias correspondientes a las líneas en vez de ejecutarse para la instancia correspondiente al cabezal, tendremos que agregar en la definición de la regla, la cláusula Level seguida de uno o varios atributos del segundo nivel:Msg(‘La fecha de la factura es mayor a la fecha actual’) if InvoiceDate>&Today Level InvoiceDetailAmount;

Page 99: Aplicaciones Genexus

96

Agregar la cláusula Level a una regla solamente tiene sentido si a continuación de la misma se mencionan atributos que son de algún nivel posterior a los niveles de los atributos implicados en la definición de la regla en sí.

En el ejemplo que sigue, el hecho de haber agregado la cláusula Level a la regla no aporta más información de la ya aportada por el atributo implicado en la definición de la regla en sí:

Msg(‘La fecha de la factura es mayor a la fecha actual’) if InvoiceDate > &Today Level CustomerId;

Es fácil comprender que el atributo InvoiceDate ya le da la pauta a GeneXus de que se trata de una regla asociadaal primer nivel, así que lo especificado por la cláusula Level en el ejemplo no aporta más información y por lo tanto su agregado es innecesario.

Por último, en el ejemplo que sigue:

InvoiceDetailDiscount= InvoiceDetailAmount * CustomerDiscountPercentage/100 Level InvoiceDate;

si bien se incluyó la cláusula Level en la definición de la regla, como el atributo que sigue a la cláusula es de un nivel superior al nivel de los atributos referenciados en la regla, la cláusula Level definida no aportará información útil en este caso tampoco. Es decir, no es posible que habiendo involucrados atributos de un segundo nivel en una regla, la misma se ejecute en el primer nivel, ya que en el primer nivel no se tiene la información del o de los niveles inferiores (además de que hay N instancias para el o los niveles inferiores). De modo que la regla seguirá estando asociada al segundo nivel de la transacción “Invoice”, no habiendo aportado información útil la cláusula Level en este ejemplo.

Concluyendo, la cláusula Level solamente tiene sentido que sea agregada para modificar el nivel por defecto de disparo de una regla, a un nivel posterior.

¿Cómo condicionar reglas para que se ejecuten en determinados modos?

GeneXus provee las siguientes funciones booleanas para poder incluirlas en la condición de disparo de las reglascon el objetivo de limitarlas a que se ejecuten puntualmente en algunos de los modos posibles:

• Insert• Update• Delete

Ejemplos de uso (todas las reglas corresponderán a la transacción “Invoice”)

1) Noaccept( InvoiceDate ) if Update;

Si se está modificando una factura (modo Update), no se permite que se modifique su fecha. Si se definiera la regla sin la condición de disparo que hemos explicitado, el atributo InvoiceDate se deshabilitaría en todos los modos de ejecución.

2) Error( ‘No se permite eliminar facturas’ ) if Delete;

Si se intenta eliminar una factura, se disparará el error deteniendo la eliminación. Como no hay atributos involucrados en la regla, por defecto el nivel asociado a la regla será el primero.

3) Error( ‘No se permite eliminar líneas de facturas’ ) if Delete Level InvoiceDetailQuantity;

Si se intenta eliminar una línea de una factura, se disparará el error deteniendo la eliminación. Observar que se ha explicitado en la regla la cláusula Level seguida de un atributo del segundo nivel de la transacción “Invoice”, para indicar que se desea que la misma esté asociada al segundo nivel de la transacción.

Page 100: Aplicaciones Genexus
Page 101: Aplicaciones Genexus

97

Fórmulas

Page 102: Aplicaciones Genexus

98

• Definir fórmulas nos brinda una forma clave de compartir conocimiento y obtener código generado optimizado

• Cuando el valor de un atributo o variable puede calcularse a partir de otros atributos, constantes y/o funciones, puede definirse como una fórmula

• Contamos con 2 formas de definir fórmulas:

- Globales: A nivel de la Base de Conocimiento- Locales: En medio de cierto código

Veremos esteconcepto enprimer lugar

Veremos este concepto más adelantecon más conocimientos de GeneXus

FórmulasObjetivos y Definición

Cuando definimos una fórmula, GeneXus puede combinar la consulta / cálculo asociada a la fórmula con la consulta en la cual la fórmula está presente y así generar sentencias optimizadas.

Page 103: Aplicaciones Genexus

99

• Fórmula Global = atributo al cual el analista GeneXus le asigna un cálculo asociado.

• Sólo atributos pueden definirse como fórmulas globales, no variables.

• ¿Cómo se realiza esta definición?

FórmulasGlobales

Accediendo al editor de fórmulas desde la estructura de la transacción

Page 104: Aplicaciones Genexus

100

• Decimos que:

Significando que:

• No se crean como atributos físicos.• Para cada objeto que referencie un atributo fórmula global, GeneXus incluirá en su programa generado el código necesariopara realizar el cálculo y desplegarlo en tiempo de ejecución.

• Tabla base / Tabla asociada a un atributo fórmula global:

• Tabla en la cual el atributo se almacenaría si no fuera fórmula.

FórmulasGlobales

atributos fórmula globales = atributos virtuales

Como explicamos en esta diapositiva, los atributos definidos como fórmula global, no se crean como camposfísicos en tablas, por lo cual decimos que son atributos virtuales.

Sin embargo, decimos que tienen una tabla “asociada” o tabla “base”, para conocer el contexto en el cual se han definido, y contar con ese contexto al momento de disparar el cálculo correspondiente donde sea que se referencien.

Page 105: Aplicaciones Genexus

101

FórmulasClasificación

• Horizontales: Una o varias expresiones aritméticas

• Aggregate: Sum, Count, Average, Max, Min, Find

• Compuestas: Conjunto de expresiones Horizontalesy/o Aggregate

Importante:

- Cuando definimos fórmulas en GeneXus no indicamos clasificación.

- La clasificación es externa a GeneXus y su finalidad es agrupar fórmulaspor:

Tipo de cálculo que ofrecen.Atributos que se pueden involucrar en su definición.

TODAS PERMITEN QUE SE LES INCLUYA CONDICIÓN DE DISPARO

APLICA A GLOBALES Y LOCALES

Page 106: Aplicaciones Genexus

102

FórmulasClasificación

• Ejemplo de Fórmula Horizontal (Global) :

CustomerTotalPurchases – CustomerTotalPayments

{ CustomerId*CustomerNameCustomerTotalPurchasesCustomerTotalPaymentsCustomerBalance}

Customer

TABLA CUSTOMER

CustomerId*CustomerNameCustomerTotalPurchasesCustomerTotalPayments

DEJA DE PERTENECER FÍSICAMENTE A LA TABLA

En la definición de un atributo como fórmula horizontal, es posible involucrar atributos pertenecientes a la tabla asociada al atributo que se está definiendo fórmula y a su tabla extendida.

En el ejemplo, al definir que el atributo CustomerBalance es fórmula, el mismo dejará de existir como campo físico de la tabla CUSTOMER.

Diremos a partir de ese momento CustomerBalance es un atributo virtual y que su tabla “base o asociada” seráCUSTOMER, ya que de almacenarse dicho atributo nuevamente (ya sea por definir el analista que deja de ser fórmula o que es fórmula redundante) se crearía como atributo físico en la tabla CUSTOMER.

El tipo de cálculo de esta fórmula definida es horizontal, ya que consiste en una expresión aritmética; por lo tanto los atributos que se pueden referenciar en la definición de esta fórmula son los pertenecientes a la tabla CUSTOMER (tanto almacenados como fórmulas) y su tabla extendida.

Page 107: Aplicaciones Genexus

103

ProductPrice*InvoiceDetailQuantity if InvoiceDetailQuantity<=100;ProductPrice*InvoiceDetailQuantity*0.9 otherwise;

FórmulasClasificación

• Ejemplo II de Fórmula Horizontal (Global) :

{ InvoiceId*CustomerIdCustomerNameInvoiceDateDetail{

InvoiceDetailId*ProductIdProductDescriptionProductPriceInvoiceDetailQuantityInvoiceDetailAmount

}}

Invoice

En este ejemplo el atributo InvoiceDetailAmount ha sido definido como fórmula global también. Es decir, utilizando el editor de fórmulas, se ha asociado un cálculo a este atributo y el mismo pasará a ser un atributo virtual.

La tabla asociada al atributo InvoiceDetailAmount será INVOICEDETAIL, ya que de almacenarse dicho atributo nuevamente, se crearía en dicha tabla física.

Como podemos observar la fórmula definida cae en la clasificación de horizontal, ya que consiste en 2 expresiones aritméticas condicionales. Los atributos involucrados en la definición de la fórmula pertenecen o bien a la tabla INVOICEDETAIL o bien a su tabla extendida.

Page 108: Aplicaciones Genexus

104

{ InvoiceId*CustomerIdCustomerNameInvoiceDateInvoiceDetails Count(InvoiceDetailQuantity)InvoiceAmount Sum(InvoiceDetailAmount)Detail{

InvoiceDetailId*ProductIdProductDescriptionProductPriceInvoiceDetailQuantityInvoiceDetailAmount

}}

Invoice

FórmulasClasificación

• Ejemplos de Fórmulas Aggregate (Globales) :

En ambos cálculos solo intervienen los registros que cumplen:

INVOICEDETAIL.InvoiceId = INVOICE.InvoiceId

En el ejemplo los atributos InvoiceDetails e InvoiceAmount han sido definidos como fórmulas globales, ya que utilizando el editor de fórmulas se ha definido una fórmula para cada uno de estos atributos (pasando ambos a ser atributos virtuales).

Dado que las fórmulas definidas son Count y Sum respectivamente, en ambos casos se trata de fórmulas Aggregate.

La tabla asociada a ambos atributos fórmula es INVOICE, ya que de almacenarse estos atributos, se crearían en dicha tabla física.

Las fórmulas Aggregate no solo tienen una tabla base asociada (como todas las formulas), sino que también involucran unatabla a ser navegada.

Si bien resulta intuitivo, la tabla a ser navegada en una fórmula Aggregate, es la tabla que se navegará para realizar el cálculo. GeneXus inferirá cuál es la tabla a ser navegada por una fórmula Aggregate, por los atributos involucrados en la definición de la fórmula. En nuestro ejemplo, la tabla a ser navegada en ambas fórmulas Aggregate es INVOICEDETAIL, yaque tanto en la definición de Sum como Count, hemos referenciado a un único atributo asociado a INVOICEDETAIL.

Cuando definimos una fórmula Aggregate, ya tenemos conocimiento de qué tabla pretendemos navegar para efectuar el cálculo. Los atibutos que podremos referenciar en la definición de una fórmula Aggregate deberán pertenecer a la tabla a ser navegada y su tabla extendida + a la tabla asociada al atributo que se está definiendo como fórmula y su tablaextendida. De involucrar en una fórmula Aggregate atributos que no pertenezcan a este contexto mencionado, un error se reportará en el listado de navegación correspondiente.

Por último, de haber atributos en común (de igual nombre) en las tablas involucradas en la definición de una fórmula, GeneXus aplicará esa relación (es decir, filtrará automaticamente por igualdad por los atributos de igual nombre). Esto es lo que sucede en estos 2 ejemplos, que GeneXus cuenta y suma las líneas relacionadas a sus cabezales (al sumar y contar, aplica automáticamente el filtro INVOICEDETAIL.InvoiceId = INVOICE.InvoiceId ).

Page 109: Aplicaciones Genexus

105

Sintaxis completa de Sum, Count, Average:

Sum | Count | Average( Expresión, [Condición Explícita, Valor por Defecto]) [if CondiciónDisparo];

En los 2 ejemplos de fórmulas Sum y Count que hemos visto, solamente hemos definido el parámetro obligatorio, es decir la expresión a ser sumada o contada (que en un caso consistió en un atributo almacenado y en otro caso en un atributo fórmula). También dicha expresión podríahaber involucrado constantes y/o funciones.

Vimos que GeneXus determina condiciones de filtro implícitas al realizar la suma, cuenta o promedio. También podríamos haber definido condiciones de filtro explícitas y en caso de haberlas, GeneXus tendrá en cuenta a ambas: implícitas + explícitas.

A su vez opcionalmente es posible definir un valor por defecto a ser retornado cuando no se encuentran registros para contar, sumar o promediar.

Al igual que todas las fórmulas, estas también permiten incluir condición de disparo.

Por último, vale mencionar una excepción y es que en particular en las fórmulas Count, el primer parámetro debe corresponder a un atributo y no a una expresión. Puede referenciarse cualquieratributo de la tabla en la cual se quieran contar registros (que cumplan con condiciones explícitasy/o implícitas).

Page 110: Aplicaciones Genexus

106

{ProductId*ProductDescriptionPriceList{

ProductPriceListDate*ProductPriceListPrice

}}

Product

FórmulasClasificación

• Ejemplos de Fórmulas Aggregate (Globales) :

{InvoiceId*

CustomerIdCustomerNameInvoiceDateInvoiceDetails Count(InvoiceDetailQuantity)InvoiceAmount Sum(InvoiceDetailAmount)Detail{

InvoiceDetailId*ProductIdProductDescriptionInvoiceDetailQuantityInvoiceDetailProductPriceInvoiceDetailAmount

}}

Invoice

InvoiceDetailProductPrice*InvoiceDetailQuantity

Max(ProductPriceListDate, ProductPriceListDate<=InvoiceDate, 0, ProductPriceListPrice)

Hemos modificado el diseño de las transacciones para que en lugar de representar que cadaproducto tiene un único precio, representamos que cada producto tiene una lista de precios de acuerdo a la fecha de cambio de los mismos.

Al efectuar este cambio, el atributo ProductPriceListPrice no podrá estar presente en el segundo nivel de la transacción Invoice. ¿Por qué? Porque el nuevo diseño estarárepresentando que un producto ya no tendrá solamente un precio, sino muchos: uno por cada fecha de cambio de precio del mismo. Por lo tanto, para un producto en una línea de una factura, tendremos que “buscar” el precio vigente del mismo, teniendo en cuenta la fecha de la factura.

Recordemos que los atributos que se pueden inferir en determinado nivel de una transacción, son los que pertenecen a la tabla extendida de la tabla base asociada al nivel en cuestión. En este ejemplo, la tabla extendida de la tabla INVOICEDETAIL, no incluye a la tabla PRODUCTPRICELIST (en la cual se encuentra el atributo ProductPriceListPrice):

por lo tanto en el nivel Detail de la transacción Invoice (asociado a la tabla INVOICEDETAIL) no es posible inferir al atributo ProductPriceListPrice (almacenado en la tabla PRODUCTPRICELIST).

Page 111: Aplicaciones Genexus

107

¿Qué ocurre si dejamos al atributo ProductPriceListPrice en el nivel Detail de la transacción Invoice? Como no se podrá inferir, entonces GeneXus no tendrá otra opción que determinar almacenarlo en la tabla INVOICEDETAIL pese a que ya estará este atributo secundario en otra tabla (PRODUCTPRICELIST). Como el resultado de esto es un modelo de datos no normalizado, se reportará el error al querer reorganizar la base de datos.

¿Y cómo hacemos para desplegar en cada línea de la factura, el precio vigente del producto de la misma? ¿De todos los precios correspondientes al producto de una línea, cuál queremos recuperar? Evidentemente, de todos los precios que tengan fecha menor o igual a la fecha de la factura, queremos aquel que tenga fecha mayor.

Procedemos entonces a crear en el nivel Detail de la transacción Invoice, un nuevo atributo de nombre InvoiceDetailProductPrice, al que definiremos como fórmula global y por lo tanto será un atributo virtual.

Le asociaremos a dicho atributo la fórmula Max:

GeneXus inferirá la tabla a ser navegada por el último parámetro de la fórmula (el atributo de retorno).

Como ya se ha explicado, los atibutos que podremos referenciar en la definición de una fórmulaAggregate deberán pertenecer a la tabla a ser navegada y su tabla extendida + a la tablaasociada al atributo que se está definiendo como fórmula y su tabla extendida. De involucraratributos que no pertenezcan a este contexto mencionado, un error se reportará en el listado de navegación correspondiente.

GeneXus considerará al momento de efectuar la búsqueda, la condición explícita de filtro + lascondiciones ímplicitas detactadas.

La fórmula Min es totalmente análoga a Max, con la única diferencia de que al encontrar un conjuntode registros que cumplan con las condiciones, se seleccionará aquel registro que tenga valor mínimo para el atributo indicado en el primer parámetro y se retornará el valor de retorno que se haya indicado en el último parámetro.

La fórmula Find por su parte, también permite buscar un registro que cumpla con ciertascondiciones, sin embargo de haber más de 1 registro que cumpla con ellas, la fórmula devolverá el atributo de retorno correspondiente al primer registro encontrado (sin maximizar ni minimizar un valor en el conjunto de registros que cumplan con las condiciones). La sintaxis Find es:

Find (Expresión de retorno, [Condición explícita], [Valor por defecto]) [if Condición de disparo]

Max(ProductPriceListDate, ProductPriceListDate<= InvoiceDate, 0, ProductPriceListPrice)

Atributo a maximizar de entre los registros que cumplan las condiciones

Para el registro encontrado, se retorna este atributo

Valor de retorno si no se encuentra ningún registro que cumpla con las condiciones

Condiciones que deben cumplir los registros para ser considerados

Page 112: Aplicaciones Genexus

108

Sum(InvoiceAmount) / Count(InvoiceAmount)

FórmulasClasificación

• Ejemplo de Fórmula Compuesta (Global):

{ CustomerId*CustomerNameCustomerTotalPurchasesCustomerTotalPaymentsCustomerBalanceCustomerAverage

}

Customer

Page 113: Aplicaciones Genexus
Page 114: Aplicaciones Genexus

109

Comunicaciónentre objetos

Page 115: Aplicaciones Genexus

110

Comunicación entre objetos

Procedimiento

Procedimiento PDF

TransacciónWeb Panel

Data Provider

Los objetos GeneXus pueden comunicarse entre ellos o con otros programas externos.

Un objeto GeneXus puede llamar o ser llamado por otro objeto, intercambiando información a través de parámetros.

Veremos a continuación cómo invocar desde un objeto a otro, y cómo especificar los parámetros (en el objeto llamador y en el llamado) para el intercambio de la información.

El esquema presentado arriba ilustra las posibles interacciones entre objetos GeneXus para una aplicación Web. Obsérvese que la flecha simple entre Web Panel y Procedimiento PDF (así como entre Transacción y Procedimiento PDF) indica que un Web Panel podrá invocar a un Procedimiento PDF pero un Procedimiento PDF no podrá invocar a un Web Panel (o transacción Web).

Page 116: Aplicaciones Genexus

111

2 posibilidades:

1)

2)

Comunicación entre objetos

PgmName.Call(par1 , …, parN)

att|&var = PgmName.Udp(par1, …, parN)

Parm(par1 , …, parN); /*Declaración de parámetrosen el objeto invocado*/

Parm(par1, …, parN , parsalida);

/*Invocación a PgmName*/

/*Declaración de parámetrosen el objeto invocado*/

/*Invocación a PgmName*/

puede omitirse

CALL - Permite invocar a un objeto GeneXus o a un programa externo, tanto sin pasarle parámetros, como pasándole.

UDP (User Defined Procedure) - Permite invocar a un objeto GeneXus o programa externo tanto sin pasarle parámetros como pasándole, y con la particularidad de que el programa llamado retornará necesariamente al menos un valor al programa que lo invocó. En ambientes Web, un objeto con interfaz una vez invocado no devuelve el control al llamdor, por lo que UDP se utiliza únicamente para invocar a Procedimientos y Data Providers (debido a que estos cumplen la condición de ejecutar y devolver el control al llamador).

Una invocación (ya sea con CALL o UDP) podrá escribirse en distintas partes del objeto llamador, dependiendo de si el mismo es una transacción, web panel, procedimiento, etc.

A su vez UDP puede utilizarse también en la definición de un atributo fórmula. Es decir, se define que cierto atributo es una fórmula y que la definición de la misma consiste en la invocación a un procedimiento utilizando UDP.

Cuando en la sintaxis de la invocación se escribe el nombre del objeto invocado y ningún método de invocación, se asume que se está invocando con udp, por lo que puede omitirse y escribirsedirectamente:

att|&var = PgmName( par1, ..., parN)

PARM – Cuando un objeto es invocado desde otro con parámetros, debe tener declarada la lista de parámetros que recibe. Esta declaración se realiza mediante la regla: PARM.

A continuación daremos más detalles acerca del uso de CALL, UDP y PARM.

Page 117: Aplicaciones Genexus

112

2 posibilidades – Ejemplos:

1) Desde  la  transacción  Invoice invocamos un procedimiento para  imprimir la factura: 

2) Ej:

ListInvoice.Call(InvoiceId)

&discount = GetDiscount.udp(ProductId,CustomerId)

Parm(InvoiceId)

Parm(ProductId,CustomerId , &disc);

Comunicación entre objetos

Y en las reglas del procedimento ListInvoice:

En el proc GetDiscount

Aquí mostramos un ejemplo de uso de CALL para realizar una invocación y otro ejemplo de uso de UDP.

Dependiendo de qué objeto llamador se trate, estas invocaciones podrán escribirse en una sección u otra del mismo, pero independientemente de eso, aquí apuntamos a mostrar que CALL permite invocar a un objeto con estilo de invocación a un programa, mientras que UDP invoca a un objeto con estilo de invocación a una función.

En el primer ejemplo se está utilizando CALL para invocar a un procedimiento pdf (objeto ListInvoice) pasándole un parámetro (InvoiceId). En el procedimiento invocado se ha declarado el parámetro que recibe (en su sección de reglas, mediante la regla parm).

En el segundo ejemplo se está utilizando UDP para invocar a un procedimiento (objeto GetDiscount) pasándole dos parámetros (ProductId, CustomerId). Ahora, observemos en la sintaxis de la invocación al procedimiento, que el mismo retorna un valor (en la variable &disc). Por este motivo, en el procedimiento invocado se han declarado tres parámetros utilizando la regla parm: los dos parámetros recibidos + el parámetro de retorno en último lugar.

Podemos ver entonces que cuando se utiliza CALL para invocar a un objeto enviándole N parámetros, se deben declarar los N parámetros (posicionales y del mismo tipo de datos que los enviados) en el objeto invocado mediante la regla parm.

En cambio cuando se utiliza UDP para invocar a un objeto enviándole N parámetros (a menos que se trate del caso particular de un Data Provider, caso que veremos más adelante):

• en la regla parm del objeto invocado se deben declarar N + 1.• El último parámetro declarado en la regla parm del objeto invocado corresponde al que se encuentra al principio de todo en la invocación, es decir, al que recibe el valor retornado.• En algún lugar del objeto invocado se le deberá asignar valor al parámetro de retorno.

Page 118: Aplicaciones Genexus

113

¿Qué declarar en la regla parm: variable o atributo?

• Variable: Se  podrá utilizar  libremente,  en  la  lógica  del  objeto invocado:

• como condición de filtro por =, >, >=, <, <=, LIKE, etc.

• para alguna operación aritmética.

• como bandera.

• etc. 

• Atributo: Automáticamente  el  mismo  actuará como  filtro  por igualdad  en  el  objeto,  no  siendo  posible  modificar  el  valor recibido.

Al definir una invocación a un objeto (ya sea utilizando CALL o UDP), si se tienen que enviar datos por parámetro al objeto invocado, resulta evidente determinar si enviar atributos y/o variables: si un dato a ser enviado por parámetro, se encuentra en el objeto invocador, en un atributo, habrá que enviar el mismo; y si se encuentra en una variable, habrá que enviar la variable.

Sin embargo, al declarar la lista de parámetros en el objeto invocado, el programador GeneXusdeberá decidir para cada parámetro, si declararlo mediante un atributo o una variable, independientemente de cómo haya sido enviado.

¿Cuál es la diferencia entre declarar un parámetro como variable o como atributo en la regla parmdel objeto invocado? Si se declara una variable, se la podrá utilizar libremente en la lógica del objeto invocado: se la podrá utilizar como condición de filtro por igualdad, por mayor, mayor o igual, menor, menor o igual, LIKE, etc.; se la podrá utilizar para alguna operación aritmética, como bandera, o lo que se necesite. Si en cambio se declara un atributo, automáticamente el mismo actuará como filtro por igualdad en el objeto, no siendo posible modificar el valor recibido.

Cuando lleguemos a la etapa del curso en la cual podamos invocar a procedimientos pdf para listados, pasándoles parámetros, así como a otros objetos, podremos terminar de comprender mejor este tema.

Page 119: Aplicaciones Genexus

114

Definición de tipo de pasaje de parámetros (in, out, inout)

• Para cada parámetro que se declara en la regla parm, es posible definir si se desea que el mismo opere:

− de entrada (in)− de salida (out) − de entrada‐salida (inout)

• Ejemplo: parm( out:&par1, in:&par2, &par3, inout:&par4);

• Ventajas:• Mejor especificación de la semántica de las interfaces.• Independencia del lenguaje de generación.• Optimizar el  pasaje de  parámetros de  las aplicaciones de  acuerdo a  la 

arquitectura en  la  que éstas se  implementan (ventaja  contrapuesta  a  la anterior).

Como se puede percibir claramente en la sintaxis del ejemplo, el primer parámetro definido es de salida, el segundo parámetro es de entrada, y el cuarto parámetro es de entrada-salida. Cuando no se especifica nada, como es el caso del tercer parámetro de la sintaxis, dependerá de lo siguiente:

• si el objeto fue invocado con CALL, el parámetro, será de entrada-salida.• si el objeto fue invocado con UDP, y se trata del último parámetro, será de salida; y si se trata de otro parámetro distinto del último, dependerá del lenguaje de generación.

Declarar explícitamente cómo se desea que cada parámetro opere, tiene las siguientes ventajas:

1. Mejor especificación de la semántica de las interfaces; es decir, tanto para GeneXus como para el programador cuando trabaje con un objeto, será claro:

- si el mismo vendrá con valor y luego de la ejecución del objeto invocado, se devolverá al objeto invocador el valor con que haya quedado (inout).- si el mismo vendrá con valor y luego de la ejecución del objeto invocado, no se devolverá al objeto invocador el valor con que haya quedado (in).- si el mismo no vendrá con valor y luego de la ejecución del objeto invocado, se devolveráal objeto invocador el valor que tenga (out).

2. Independencia del lenguaje de generación; es decir, si se define explícitamente cómo se desea que cada parámetro opere, al generar las aplicaciones utilizando diferentes lenguajes de generación no estarácambiando el comportamiento de los parámetros en base al comportamiento por defecto del lenguaje de generación correspondiente.

3. Optimizar el pasaje de parámetros de acuerdo a la arquitectura en la que éstas se generen (siendo una ventaja contrapuesta a la anterior); esto se refiere a lo siguiente: para la mayoría de los lenguajes es más eficiente pasar los parámetros por referencia (inout) que por valor (in / out); pero en Java, por ejemplo, los parámetros solo se pueden pasar por valor, por lo que para lograr la funcionalidad de pasarlos por referencia es necesario hacer conversiones de parámetros, lo cual puede redundar en un overhead importante; por otro lado, cuando se trata de aplicaciones distribuidas (por ejemplo Java con RMI o HTTP), la utilización de parámetros de tipo out tiene la ventaja de que no es necesario enviar al parámetro en la invocación, a diferencia de si los parámetros se definen de inout (que implica que haya que pasar todos los parámetros); esto tiene como consecuencia que se envíen más bytes de los necesarios, lo cual es inconveniente especialmente en entornos tales como Internet.

Page 120: Aplicaciones Genexus

115

Más posibilidades para definir invocaciones Función Link

1)

2)

Comunicación entre objetosWeb

control.Link = PgmName.Link([,par1 …, parN])

Ej: imagen.Link = Link(‘http://www.artech.com.uy’)

Ej: imagen.Link = Customer.Link()

control.Link = Link(URL)

Los parámetros son opcionales, y en caso de haber, se declaran con regla parm

La función Link se asocia a la propiedad link de un control dentro de cualquier evento de una transacción o web panel, teniendo como resultado que al hacer clic sobre dicho control se realizará la llamada al objeto o URL referenciada en el link.

PgmName (el objeto invocado) podrá ser un web panel, transacción, o procedimiento PDF1.

---------------------------------------------------------------------------------------------------------------------------------1 También un procedimiento HTTP, pero no profundizaremos sobre este concepto en este curso

Page 121: Aplicaciones Genexus

116

Más posibilidades para definir invocaciones  Comando Link

1)

2)

Comunicación entre objetosWeb

Ej: Customer.Link(CustomerId)

PgmName.Link([,par1 …, parN])

Ej: Link(‘http://www.google.com’)

Link(URL)

El comando Link puede ser utilizado dentro de cualquier evento de una transacción o web panel1.

Cuando se ejecute el evento, al llegar a la sentencia con el comando Link, se redireccionará en forma automática a la URL especificada.

En caso de utilizarse el comando Link como en el ejemplo 1, invocando a un PgmName (siendo PgmName un web panel, transacción o procedimiento PDF), será equivalente a la utilización de Call. Opcionalmente se podrán pasar parámetros al objeto invocado, debiendo declararse los mismos en el objeto llamado, con la regla parm.

--------------------------------------------------------------------------------------------------------------------------------1 También un procedimiento HTTP, pero no profundizaremos sobre este concepto en este curso.

Page 122: Aplicaciones Genexus
Page 123: Aplicaciones Genexus

117

Orden de ejecución de reglas y fórmulas

Page 124: Aplicaciones Genexus

118

“Category”CategoryId*CategoryDiscount

“Customer”CustomerId*CustomerNameCategoryIdCustomerTotalPurchases

“Shipping”ShippingDate*ShippingCharge

Add( InvoiceTotal, CustomerTotalPurchases);Error( ‘Insufficient Stock’ ) if ProductStock<0;Subtract( InvoiceDetailQuantity, ProductStock);

InvoiceId*InvoiceDateCustomerIdCustomerTotalPurchasesCategoryDiscountInvoiceDiscount = InvoiceSubTotal *CategoryDiscountInvoiceShippingCharge = Max( ShippingDate, ShippingDate

<=InvoiceDate,,ShippingCharge)InvoiceSubTotal = SUM( InvoiceDetailAmount )InvoiceTotal = InvoiceSubTotal – InvoiceDiscount

+ InvoiceShippingCharge(ProductId*ProductPriceProductStockInvoiceDetailQuantityInvoiceDetailAmount) = InvoiceDetailQuantity *

ProductPrice

“Product”ProductId*ProductPriceProducStock

Transacción "Invoice"

Reglas:

Orden de ejecución dereglas y fórmulas

La forma de programar el comportamiento de las transacciones es definiendo reglas, las cuales se escriben de forma declarativa. A su vez si hay cálculos para efectuar, se puede optar por la alternativa de definir atributos fórmula.

El programador GeneXus en ningún momento especifica la secuencia de ejecución de las reglas y fórmulas definidas en una transacción, sin embargo al momento de generar, GeneXus determina las dependencias existentes entre las reglas y fórmulas definidas.

Supongamos que estamos definiendo una aplicación para una empresa que vende determinados productos, y que cuenta con un servicio de entrega a domicilio que lleva la mercadería a sus clientes. Y definimos entre otras, las siguientes 5 transacciones:

"Customer" (para registrar los clientes de la empresa)“Category” (a las que pertenece cada cliente)“Shipping” (envíos: guarda un histórico de costos de envío)"Invoice" (facturas que se emiten a los clientes)"Product" (productos vendidos por la empresa)

Se resalta la estructura de la transacción "Invoice", con sus atributos fórmulas y sus reglas declaradas.

¿En qué orden se dispararán las reglas y fórmulas de la transacción "Invoice"?

Page 125: Aplicaciones Genexus

119

R. Add(InvoiceTotal, CustomerTotalPurchases);F. InvoiceTotal = InvoiceSubTotal - InvoiceDiscount +

InvoiceShippingChargeF. InvoiceDiscount = InvoiceSubTotal*CategoryDiscountF. InvoiceShippingCharge = MAX( ShippingDate, ShippingDate <=

InvoiceDate,,ShippingCharge)F. InvoiceSubTotal = SUM( InvoiceDetailAmount )F. InvoiceDetailAmount = InvoiceDetailQuantity *ProductPriceR. Subtract(InvoiceDetailQuantity, ProductStock) ;R. Error( ‘Insuffcient Stock’) if ProductStock < 0 ;

Árbol de evaluación

error (‘Insufficient Stock ’)

ProductStock

InvoiceDetailQuantity

InvoiceDetailAmount

InvoiceTotal

InvoiceSubTotal

InvoiceDiscount

ProductPrice

CategoryDiscount

CustomerTotalPurchases

InvoiceShippingCharge

InvoiceDateShippingDate

ShippingCharge

Al momento de generar el programa asociado a la transacción "Invoice", GeneXus extraerá las dependencias existentes entre las reglas y fórmulas definidas; construirá lógicamente un árbol de dependencias (o árbol de evaluación) que determinará la secuencia de evaluación.

Podemos imaginar que el árbol se ejecuta de abajo hacia arriba, es decir que cada vez que cambia el valor de un atributo, se ejecutan todas las reglas y fórmulas que dependen de ese atributo (y que en el árbol se encuentran hacia arriba).

Por ejemplo, si cambia la cantidad de una línea de una factura (InvoiceDetailQuantity), como este atributo interviene en la fórmula que calcula el importe de la línea (InvoiceDetailAmount), dicha fórmula se redisparará. Por cambiar el importe de una línea, deberá redispararse la fórmula correspondiente al subtotal de la factura (InvoiceSubTotal) y en consecuencia, también deberá recalcularse la fórmula correspondiente al descuento (InvoiceDiscount), ya que depende del subtotal. Deberá redispararse también la fórmula correspondiente al total de la factura (InvoiceTotal) ya que depende tanto del valor de InvoiceSubTotal como del valor de InvoiceDiscount. Por último, por cambiar el total también se tendrá que disparar la regla Add(InvoiceTotal, CustomerTotalPurchases);.

Además de dispararse todas las fórmulas y reglas involucradas en la rama derecha del árbol desde el atributo InvoiceDetailQuantity, también se dispararán las fórmulas y reglas involucradas en la rama izquierda. Es decir, que al cambiar el valor del atributo InvoiceDetailQuantity, se redisparará también la regla Subtract(InvoiceDetailQuantity, ProductStock); y en consecuencia, por modificar esta regla el valor del atributo ProductStock, se evaluará si habrá que disparar la regla Error(‘Stock Insuficiente’) if ProductStock < 0;

Concluyendo, las reglas y fórmulas que se definen en una transacción suelen estar interrelacionadas y GeneXus determina las dependencias entre ellas así como su orden de evaluación.

Page 126: Aplicaciones Genexus

120

Observemos las 2 últimas reglas definidas:Subtract(InvoiceDetailQuantity, ProductStock);Error(‘Insufficient Stock’) if ProductStock < 0;

Estas reglas están interrelacionadas porque las dos involucran al atributo ProductStock. Ahora, mientras la segunda solamente consulta su valor, la primera lo actualiza. Entonces, la regla que actualiza al atributo será la que se disparará primero, y luego se disparará la que lo consulta.

Toda regla que actualice el valor de un atributo se disparará antes que una regla que lo consulte (esto se puede observar claramente en el árbol). Por este motivo es que la regla Error consulta si el atributo ProductStock quedócon valor negativo; porque como dijimos la sustracción se realizará primero.

En la programación clásica se suele consultar primero si alcanza el stock, y en caso de que sea suficiente recién se hace la sustracción. Por eso quienes están aprendiendo GeneXus pueden intuitivamente escribir la regla: Error(‘Insufficient Stock') if InvoiceDetailQuantity > ProductStock. Esta sintaxis es correcta, sin embargo no es correcta su lógica ya que como venimos explicando, en el árbol de evaluación determinado por GeneXus primero se disparará la regla Subtract y luego la regla Error; por lo tanto tendremos que especificar que se dispare el mensaje de error si es que quedó el stock con valor negativo, dado que ya se habrá ejecutado la sustracción al momento de consultar el valor de ProductStock.

Así que la regla que se debe definir es:

Error(‘Insufficient Stock’) if ProductStock < 0;

Y no:

Error('Insufficient Stock') if InvoiceDetailQuantity > ProductStock;

Cuando se dispara una regla Error, se detiene cualquier actualización a la base de datos y se desarma el árbol de evaluación, quedando todo en el estado anterior a producirse el error. Siguiendo el ejemplo que veníamos viendo, si al dispararse la regla Subtract el stock quedara negativo, se dispararía la regla Error. Como consecuencia de dispararse la regla Error, se desharía el Subtract que se había ejecutado, así como todas las demás reglas y fórmulas que se hayan ejecutado (recálculo de los atributos InvoiceDetailAmount, InvoiceSubTotal, ...., CustomerTotalPurchases).

Page 127: Aplicaciones Genexus

121

Alteraciones del orden de disparode las reglas

SupplierId*InvoiceId*...InvoiceEntTotal Entered Total

( ProductId*InvoiceDetailQuantityInvoiceDetailPriceInvoiceDetailAmount = InvoiceDetailPrice * InvoiceDetailQuantity)

...InvoiceCalcTotal = SUM(InvoiceDetailAmount) Calculated Total

Error

Total Calculado

Total Ingresado

InvoiceDetailAmount

Error(‘The calculated total doesn’t match with the entered total') if (InvoiceEntTotal<>InvoiceCalcTotal) On AfterLevel Level ProductId;

En la mayoría de los casos el orden de ejecución de las reglas definido por GeneXus a partir de nuestras especificaciones es el deseado. Pero en algunos casos podemos querer cambiar el momento de disparo de una regla.

Ejemplo:Definimos una transacción para registrar las facturas que nos entregan nuestros proveedores.El identificador del primer nivel es compuesto por el identificador de proveedor y el identificador de factura, ya que el número de factura no nos sirve como identificador único, porque proveedores distintos pueden repetir el mismo número de factura.Para cada factura de un proveedor que se ingrese, nos interesa controlar que el total que venga escrito en la factura (y que se ingresará en el atributo InvoiceEntTotal) sea correcto. Para hacer este control, definimos al atributo InvoiceCalcTotal como fórmula vertical SUM(InvoiceDetailAmount), y agregamos una regla Error que se disparará si no coinciden los valores de los atributos InvoiceEntTotal y InvoiceCalcTotal:Error('El total ingresado no coincide con el total calculado') if InvoiceCalcTotal <> InvoiceEntTotal;Si construimos el árbol de evaluación correspondiente a las fórmulas y regla que hemos definido en esta transacción:

Page 128: Aplicaciones Genexus

122

vemos que las dependencias indican que cada vez que se agreguen, modifiquen o eliminen valores de los atributos InvoiceDetailPrice e InvoiceDetailQuantity en las líneas, se recalculará el valor del atributo InvoiceDetailAmount correspondiente; en consecuencia, se recalculará el valor del atributo fórmula InvoiceCalcTotal que hemos definido para tener el total calculado de la factura; y como este atributo estáinvolucrado en la condición de disparo de la regla Error, si se cumple dicha condición de disparo, se disparará la regla Error(‘El total ingresado no coincide con el total calculado’) if InvoiceCalcTotal <> InvoiceEntTotal.

Ahora, prestemos atención a que la condición de disparo “InvoiceCalcTotal <> InvoiceEntTotal” se va a cumplir repetidamente en la medida que el operador vaya ingresando líneas, porque para cada línea que se ingrese se calculará el valor del atributo fórmula InvoiceDetailAmount de la línea, y en consecuencia se recalculará el valor del atributo fórmula InvoiceCalcTotal. Pero el valor calculado de este atributo no coincidirá con el valor ingresado en el atributo InvoiceEntTotal hasta que no se hayan ingresado todas las líneas de la factura; entonces, se disparará la regla Error(‘The calculated total doesn’t match with the entered total’) if InvoiceCalcTotal <> InvoiceEntTotal;.

Concluimos entonces que en este caso no nos sirve lo que determina el árbol de evaluación, ya que no queremos que se evalúe la condición de disparo de la regla Error cada vez que el operador ingrese, modifique o elimine líneas, sino que recién necesitamos que se evalúe cuando el usuario haya terminado de trabajar con todas las líneas de la factura.

GeneXus ofrece eventos o momentos de disparo en las transacciones, que ocurren antes o después de determinada acción, como la grabación del cabezal, o de una línea. Las reglas de las transacciones pueden condicionarse de manera tal de dispararse en el preciso instante en que ocurre alguno de esos eventos de disparo. Siguiendo el ejemplo que veníamos viendo, existe un evento de disparo que ocurre luego de iterar en un nivel y salir del mismo. La sintaxis de este evento de disparo es: AfterLevel Level Atributo, debiendo ser Atributo un atributo perteneciente al nivel que se ha iterado y se abandona.

De modo que a la regla Error de nuestro ejemplo, le agregaríamos este evento de disparo, y quedaría definida de la siguiente forma:

Error(‘The calculated total doesn’t match with the entered total’) if InvoiceCalcTotal<>InvoiceEntTotal OnAfterLevel Level ProductId.

Con este evento de disparo que hemos agregado a la regla logramos controlar lo que deseábamos en el momento adecuado.

Además de este evento de disparo, existen otros que veremos a continuación.

Page 129: Aplicaciones Genexus

123

• BeforeValidate

• AfterValidate

• BeforeInsert, BeforeUpdate, BeforeDelete

• AfterInsert, AfterUpdate, AfterDelete

• AfterLevel

• BeforeComplete

• AfterComplete

Eventos de disparo

La mayoría de las reglas de transacciones permiten que se les agregue de ser necesario un evento o momento de disparo.

Al agregar un evento o momento de disparo a una regla, estaremos especificando que la regla se deberá ejecutar en ese determinado momento.

Eventos de disparo:

Al momento de la confirmación de la transacción, ocurre una serie de acciones que es necesario conocer para poder programar correctamente el comportamiento de las reglas.Para una transacción de dos niveles, podríamos enumerarlas como sigue:

• validación de los datos del cabezal• grabación física del cabezal (ya sea inserción, modificación o eliminación)• validación de los datos de la primera línea• grabación física de los datos de la primera línea• validación de los datos de la segunda línea• grabación física de los datos de la segunda línea• …• validación de los datos de la n-ésima línea• grabación física de los datos de la n-ésima línea• commit

La acción de “validación de los datos del cabezal” ocurre cuando se han validado todos y cada uno de los campos ingresados en el cabezal. Observar que en este punto ya se han disparado todas las reglas que correspondían a atributos del cabezal y que no tenían evento de disparo asociado (ejemplo: Default(InvoiceDate, &today)). Inmediatamente después se grabará el registro correspondiente al cabezal.

Análogo es el caso de las líneas: “la validación de los datos de una línea” ocurre cuando ya se han validado todos y cada uno de los datos de la línea, y también se han disparado todas las reglas correspondientes según el árbol de evaluación (ejemplo: subtract( InvoiceDetailQuantity, ProductStock)). Inmediatamente después de esta acción de validación, se grabará físicamente el registro correspondiente a la línea.

Cada transacción, al terminar de trabajar con un cabezal y sus líneas, realiza un commit (es automático; será colocado en el código generado por GeneXus, a menos que el analista especifique lo contrario, como veremos más adelante). Es decir, si se van a ingresar los datos de dos facturas distintas utilizando la transacción “Invoice”, luego de ingresados los datos de la primera, se commitearán sus registros, y luego se ingresará la segunda, al cabo de lo cuál se commitearán sus registros.

Page 130: Aplicaciones Genexus

124

Los eventos de disparo de reglas permiten definir que se ejecuten antes o después de alguna de las acciones que acabamos de enumerar. Veremos cuándo ocurre cada evento de disparo.

Evento de disparo: BeforeValidateEste evento de disparo ocurre un instante de tiempo antes de que la información de la instancia con la que se estátrabajando (cabezal o línea x) sea validada (o confirmada). Es decir, ocurrirá un instante de tiempo antes de la acción de “validación del cabezal” o “validación de la línea”, según corresponda. Observar que aquí también se habrán disparado todas las reglas según el árbol de evaluación que no estén condicionadas a evento de disparo alguno.

Eventos de disparo: AfterValidate, BeforeInsert, BeforeUdate, BeforeDelete

El evento de disparo AfterValidate permite especificar que una regla se ejecute inmediatamente antes de que se grabe físicamente cada instancia del nivel al cual está asociada la regla, en la tabla física correspondiente, y después de que se hayan validado los datos de esa instancia.

En otras palabras, si se le agrega el evento de disparo AfterValidate a una regla, la misma se ejecutará para cada instancia del nivel al cual esté asociada, inmediatamente antes de que la instancia se grabe físicamente (ya sea que se inserte, modifique o elimine) como registro en la tabla física asociada al nivel.

EJEMPLOS

1. Hay veces en las que no contamos con la posibilidad de utilizar la propiedad Autonumber para numerar de forma automática y correlativa los atributos que son clave primaria simple. Tal funcionalidad es provista por los manejadores de base de datos (DBMSs) y GeneXus la aprovecha y permite usarla; sin embargo en los casos en los que no se trabaja con un manejador de base de datos, no contamos con la posibilidad de utilizar esta facilidad.

En esos casos en los que necesitamos numerar de forma automática y correlativa ciertos atributos, y no podemos utilizar la propiedad Autonumber, debemos resolverlo programándolo. Para ello solemos definir una transacción conteniendo dos atributos, uno para almacenar un literal y otro para almacenar el último número asignado automáticamente al atributo descripto por el literal; la transacción conlleva la creación de una tabla, y definimos un procedimiento que consulta esa tabla, obtiene el último número asignado para el atributo a ser numerado, le suma uno y devuelve el próximo número, además de actualizarlo en la tabla.Para invocar al procedimiento de numeración automática se debe definir en las transacciones que lo requieran una regla del siguiente estilo:

CustomerId = PGetNumber.udp( ‘CUSTOMER’ ) if Insert on AfterValidate;

En este caso se está queriendo autonumerar el atributo CustomerId de la transacción “Customer”

Del mismo modo, si queremos autonumerar el identificador de facturas, escribiríamos en la transacción “Inovice” la siguiente regla:

InvoiceId = PGetNumber.udp( ‘INVOICE’ ) if Insert on AfterValidate;

De esta forma definimos que se efectúen numeraciones automáticas en las transacciones únicamente cuando se realicen inserciones (por la condición de disparo: if Insert) e inmediatamente antes de que se grabe físicamentecada instancia a ser insertada (por el evento de disparo: on AfterValidate) a través del primer nivel de la transacción (porque en las dos reglas de invocación mostradas, hay solamente un atributo involucrado que pertenece al primer nivel de las transacciones "Customer" e "Invoice" respectivamente).

El motivo por el cual agregamos el evento de disparo on AfterValidate a estas reglas es para invocar al procedimiento de numeración automática inmediatamente antes de que se inserte el registro en la base de datos y luego de la validación, intentando de esta forma tener el mayor grado de seguridad posible de que el número asignado seráutilizado (y no perder números). Piense unos instantes el lector cuándo se dispararía la regla anterior de no estar condicionada a evento de disparo alguno, y qué podría pasar en el caso de que fallara la validación de alguno de los datos del cabezal. La respuesta es simple: se perdería un número. Es decir, si el número de factura anterior fuera 5 y el usuario quisiera ingresar la siguiente factura, la regla de asignación con udp que invoca la procedimiento de numeración se dispararía ni bien se ingresara a la transacción estando en modo insert, ya que involucra al primer atributo del cabezal. El procedimiento devolvería el número 6, y si validando los datos del cabezal se encuentra algún error que no permite continuar con el proceso, y se abandonara la transacción, por ejemplo, ese número 6 se habráperdido y la próxima factura, que correlativamente debería tener el número 6 no lo tendrá, tendrá el 7.

Page 131: Aplicaciones Genexus

125

Existen tres eventos de disparo que ocurren en el mismo momento que el AfterValidate, pero que ya contienen intrínseco el modo. Ellos son: BeforeInsert, BeforeUpdate y BeforeDelete..Es equivalente escribir la regla presentada antes como lo hicimos, a escribirla:

InvoiceId = PGetNumber.udp( ‘INVOICE’ ) on BeforeInsert;

Observar que aquí es redundante condicionar la regla a “If Insert”. Por tanto, valen las siguientes equivalencias:

on BeforeInsert ∼ If Insert on AfterValidateon BeforeUpdate ∼ If Update on AfterValidateon BeforeDelete ∼ If Delete on AfterValidate

Si hacemos un esquema de las acciones que rodean al evento de disparo, quedarán claros los dos sinónimos elegidos para este evento (AfterValidate y BeforeInsert para modo insert)

VALIDACIÓN DE LOS DATOSAfterValidate – BeforeInsert – BeforeUpdate – BeforeDeleteGRABACIÓN DEL REGISTRO (insert, update, delete según corresponda)

2) Si definimos una regla a la cual le incluimos también el evento de disparo on AfterValidate, u on BeforeInsert, BeforeDelete, BeforeUdate pero a diferencia de los ejemplos recién vistos, se referencia en la regla al menos un atributo del segundo nivel de la transacción en la cual se está definiendo la regla, la misma estará asociada al segundo nivel1. Por lo tanto, la regla se ejecutará inmediatamente antes de que se grabe físicamente cada instancia correspondiente al segundo nivel de la transacción.

Eventos de disparo: AfterInsert, AfterUpdate, AfterDelete

Así como existe un evento de disparo que permite definir que determinadas reglas se ejecuten inmediatamente antes de que se produzca la grabación física de cada instancia de un nivel (AfterValidate, BeforeInsert, BeforeUpdate, BeforeDelete), también existen eventos de disparo para definir que ciertas reglas se ejecuten inmediantamentedespués de que se inserten, modifiquen o eliminen físicamente instancias de un nivel. Estos eventos son AfterInsert, AfterUpdate y AfterDelete.

El evento de disparo AfterInsert permite definir que una regla se ejecute inmediatamente después de que se inserte físicamente cada instancia del nivel al cual está asociada la regla; el AfterUdate luego de que se actualice físicamente la instancia, y el AfterDelete luego de que se elimine.

EJEMPLOSSupongamos que en la transacción "Customer" queremos invocar a un reporte que realice la impresión de los datos de cada cliente con el cual se trabaje por medio de la transacción.

¿En qué momento debemos realizar la invocación al reporte desde la transacción?

----------------------------------------------------------------------------------------------------------------------------------------------------1 Existe otra forma de provocar que una regla que contiene atributos de un nivel determinado, se dispare en el nivel siguiente, mediante la cláusula Level que mencionamos cuando vimos conceptos importantes sobre reglas de transacciones.

tiem

po

Page 132: Aplicaciones Genexus

126

Caso 1: RPrintCustomer.call( CustomerId ) on AfterValidate;

No es adecuado agregarle este evento de disparo a la regla de invocación al reporte, porque éste se invocaría inmediatamente antes de la grabación física de cada cliente. En consecuencia, el reporte no encontraría al cliente con sus datos en la tabla CUSTOMER (si se estaba insertando un cliente por medio de la transacción), o lo encontraría con sus datos desactualizados (si se estaba modificando un cliente por medio de la transacción). Si en cambio se estaba eliminando un cliente por medio de la transacción, el reporte encontraría los datos del cliente en la tabla CUSTOMER y los listaría justamente antes de la actualización física (eliminación).

Si se desea esto, es decir, emitir un listado con los datos de cada cliente que se elimine, sería adecuado definir la siguiente regla:

RPrintCustomer.call( CustomerId ) on BeforeDelete;o su equivalente:RPrintCustomer.call( CustomerId ) if Delete on AfterValidate;

para restringir el disparo de la regla únicamente a cuando se esté eliminando un cliente, porque es el único caso en el sería correcto utilizar el evento de disparo AfterValidate (ya que justamente necesitamos emitir el reporte antes de la eliminación).

Caso 2: RPrintCustomer.Call( CustomerId ) on AfterInsert;

El evento de disparo AfterInsert ocurre inmediatamente después de que se inserte físicamente cada instancia asociada a cierto nivel de la transacción (en este caso, como el único atributo involucrado en la regla es CustomerId,se trata de una regla asociada al primer y único nivel de la transacción "Customer").

Como lo indica claramente su nombre, el evento de disparo AfterInsert sólo ocurre al insertar una nueva instancia (precisamente luego de ser insertada como registro físico). Es por ello que cuando se agrega el evento de disparo onAfterInsert a una regla, no es necesario agregarle la condición de disparo if insert.

Es correcto agregarle este evento de disparo a la regla de invocación al reporte, ya que el reporte se invocaría inmediatamente después de que se inserte físicamente cada cliente. Así que el reporte encontraría al cliente con sus datos en la tabla CUSTOMER y los imprimiría.

Lo que debe quedar claro es que con esta definición el reporte se invocará únicamente luego de realizar inserciones.

Caso 3: RPrintCustomer.Call( CustomerId ) on AfterUpdate;

El evento de disparo AfterUpdate ocurre inmediatamente después de que se actualice físicamente cada instancia asociada a cierto nivel de la transacción (en este caso, como el único atributo involucrado en la regla es CustomerId,se trata de una regla asociada al primer y único nivel de la transacción "Customer").

Es adecuado agregarle este evento de disparo a la regla de invocación al reporte, ya que el reporte se invocaría inmediatamente después de que se actualice físicamente un cliente. Así que el reporte encontraría al cliente con sus datos actualizados en la tabla CLIENTES y los imprimiría.

El reporte se invocará únicamente luego de realizar actualizaciones.

Caso 4: RPrintCustomer.Call( CustomerId ) on AfterDelete;

El evento de disparo AfterDelete ocurre inmediatamente después de que se elimine físicamente cada instancia asociada a cierto nivel de la transacción (en este caso, como el único atributo involucrado en la regla es CustomerId,se trata de una regla asociada al primer y único nivel de la transacción "Customer").

No es adecuado agregarle este evento de disparo a la regla de invocación al reporte, porque el reporte se invocaría inmediatamente después de la eliminación física de cada cliente. En consecuencia, el reporte no encontraría al cliente con sus datos en la tabla CUSTOMER.

Page 133: Aplicaciones Genexus

127

Caso 5: RPrintCustomer.Call( CustomerId ) on AfterInsert, AfterUpdate;RPrintCustomer.Call( CustomerId ) if delete on AfterValidate;

Para finalizar, estas dos reglas son las adecuadas para invocar a un reporte en la transacción "Customer", con el objetivo de imprimir los datos de cada cliente con el cual se trabaje, abarcando los tres modos de trabajo.

Como se puede observar en la primera regla es posible incluir varios eventos de disparo separados por coma, cuando los mismos aplican a una misma regla.

Es decir, es lo mismo definir estas dos reglas independientes:

RPrintCustomer.Call( CustomerId ) on AfterInsert;RPrintCustomer.Call( CustomerId ) on AfterUpdate;

que esta regla:

RPrintCustomer.Call( CustomerId ) on AfterInsert, AfterUpdate;

Caso 6: Si definimos una regla a la cual le incluimos el evento de disparo on AfterInsert, pero a diferencia de los ejemplos recién vistos, se referencia en la regla al menos un atributo del segundo nivel de la transacción en la cual se está definiendo la regla, la misma estará asociada al segundo nivel. Por lo tanto, la regla se ejecutará inmediatamente después de que se inserte físicamente cada instancia correspondiente al segundo nivel de la transacción.

Análogo es el caso de on AfterUpdate y on AfterDelete.

Ampliamos el esquema que habíamos efectuado antes, de las acciones que rodean a los eventos de disparo vistos hasta ahora:

VALIDACIÓN DE LOS DATOSAfterValidate – BeforeInsert – BeforeUpdate – BeforeDeleteGRABACIÓN DEL REGISTRO (insert, update, delete según corresponda)AfterInsert – AfterUpdate – AfterDelete

Este esquema se repite para cada instancia del nivel. Por ejemplo, pensemos en el ingreso de las líneas de una factura. Para cada línea ocurrirá este esquema, por lo que podemos pensar en un loop que se repite hasta que se termina de grabar la última línea.

La acción que sucede a la grabación de la última línea sería el abandonar ese nivel (en este caso el de las líneas de factura). Y luego de esa acción, a menos que venga otro nivel con el que se volvería a ingresar en el esquema anterior, ocurrirá la última acción en la ejecución, que es el commit. Entre la acción de abandonar el nivel, y el commit tendremos un evento (que admite dos nombres distintos) y otro para luego del commit. Son los que veremos a continuación pero que ya mostramos en esquema:

VALIDACIÓN DE LOS DATOS CABEZALAfterValidate – BeforeInsert – BeforeUpdate – BeforeDeleteGRABACIÓN DEL REGISTRO (insert, update, delete según corresponda)AfterInsert – AfterUpdate – AfterDelete

VALIDACIÓN DE LOS DATOS LÍNEAAfterValidate – BeforeInsert – BeforeUpdate – BeforeDeleteGRABACIÓN DEL REGISTRO (insert, update, delete según corresponda)AfterInsert – AfterUpdate – AfterDelete

ABANDONAR NIVEL 2AfterLevel - BeforeCompleteCOMMITAfterComplete

tiem

po

tiem

po

loop

Page 134: Aplicaciones Genexus

128

Eventos de disparo: AfterLevel, BeforeComplete

El evento de disparo AfterLevel permite definir que una regla se ejecute inmediatamente después de terminar de iterar determinado nivel.

SINTAXIS: regla [if condición de disparo] [on AfterLevel Level atributo];

DONDE: regla: es una regla de las permitidas en transaccionescondición de disparo: es una expresión booleana que permite involucrar atributos, variables, constantes y funciones, asícomo los operadores Or, And, Not. atributo: es un atributo perteneciente al nivel para el cual se desea que luego de ser iterado, se ejecute la regla.

FUNCIONALIDAD:

Si el atributo que se especifica a continuación del evento de disparo AfterLevel pertenece al segundo nivel de la transacción, la regla se ejecutará cuando se hayan terminado de iterar todas las líneas del segundo nivel.

Y si el atributo que se especifica a continuación del evento de disparo AfterLevel pertenece al primer nivel -siguiendo el mismo concepto- la regla se ejecutará cuando se haya terminado de iterar por todos los cabezales. Observar que esto se da al final de todo, es decir, una vez que se hayan ingresado todos los cabezales y sus líneas y se cierre la transacción (en ese momento se habrán iterado todos los cabezales). Por lo tanto, si el atributo especificado pertenece al primer nivel, la regla se disparará una vez sola antes del Evento Exit (es un evento que se ejecuta una sóla vez cuando se cierra una transacción en tiempo de ejecución, como veremos).

Ejemplo: Rever el ejemplo presentado antes, donde teníamos una transacción para representar las facturas que nos entregan nuestros proveedores, y donde queríamos controlar que el total calculado de cada factura coincidiera con el total ingresado. Allí teníamos la regla:

Error('El total ingresado no coincide con el total calculado') if InvoiceCalcTotal<>InvoiceEntTotal;

que necesitáramos se disparara luego de ingresadas todas las líneas de la factura. Por tanto, el evento de disparo apropiado seráAfterLevel Level att, donde att sea cualquier atributo de las líneas.

El evento de nombre BeforeComplete, en este caso, coincide con el AfterLevel. Si observamos el esquema presentado en la página anterior, podemos ver que el instante de tiempo que hay entre que se abandona el último nivel y se realiza el commit es el instante en que ocurren estos eventos. Son dos nombres para referirnos a lo mismo.

Cuidado que esto es así siempre y cuando el nivel abandonado sea el último. Supóngase por ejemplo una transacción con dos niveles paralelos. Por ejemplo, si agregamos al cliente sus direcciones de mail y sus números telefónicos (puede tener varios):

{CustomerId*CustomerName…{CustomerPhone*…}

{CustomerEMail*…}}

El momento en que deberá dispararse una regla condicionada a: On AfterLevel Level CustomerPhone NO COINCIDIRA con el de una regla condicionada a on BeforeComplete.Mientras que la primera se disparará cuando se abandona el nivel de los teléfonos, y antes de entrar a validar todos los emails, la segunda se disparará después de abandonar este último nivel.En este caso el evento BeforeComplete coincidirá con el AfterLevel Level CustomerEMail.

Evento de disparo: AfterComplete

Este evento corresponde al instante de tiempo que sucede al commit. Hablaremos más de este evento unas páginas adelante, cuando estudiemos la integridad transaccional.Si se abre la transacción de facturas, se ingresan 3 facturas (cabezal y sus respectivas líneas) y se cierra la transacción, ocurrirán 3 commits (uno al final de cada ingreso de cabezal + líneas) y 3 eventos AfterComplete.

Page 135: Aplicaciones Genexus

129

REGLAS STAND-ALONE

EVALUACION DE REGLAS YFORMULAS SEGÚN ARBOL

EVALUACION DE REGLAS YFORMULAS

SEGÚN ARBOL

PARA CADA LINEA

Interactivamente y antes de confirmar:

Ejemplo en transacción de 2 niveles

El siguiente ejemplo pretende mostrar visualmente en qué momentos se irán disparando las reglas y fórmulas definidas en una transacción.

El disparo de reglas y fórmulas se irá haciendo de acuerdo al árbol de evaluación, siguiendo el orden que éste determina.

Page 136: Aplicaciones Genexus

130

REGLAS STAND-ALONE

EVALUACION REGLAS Y FÓRMULAS SEGÚN ARBOL

AfterValidate / BeforeInsert / Update / DeleteGRABACION DEL CABEZALAfterInsert / Update / Delete

AfterValidate / BeforeInsert / Udpate / DeleteGRABACION DE LA LINEAAfterInsert/Update/Delete

AfterLevel Level attNivel2 - BeforeComplete

AfterCompleteCOMMIT

VALIDACIÓN

EVALUACION DE REGLAS YFORMULAS SEGÚN ARBOL

PARA CADA LINEA

Al confirmar los datos, se ejecutan en el siguiente orden:

VALIDACIÓN

ABANDONAR NIVEL 2

BeforeValidate

BeforeValidate

Ejemplo en transacción de 2 niveles

Reglas stand aloneLas reglas stand alone son aquellas que:1. Pueden ejecutarse con la información provista por los parámetros recibidos.2. No dependen de nada para ejecutarse.

Ejemplos de reglas stand alone (por poder ejecutarse con la información provista por los parámetros):· &A = parámetro2;· Msg( ‘...’ ) if parámetro1 = 7;

Ejemplos de reglas stand alone (por no depender de nada para ejecutarse):· msg( ‘You are in the invoice transaction’);· &A = 7;

Por lo tanto, son las primeras reglas que pueden ejecutarse.Luego de la ejecución de las reglas stand alone, se ejecutan las reglas asociadas al primer nivel de la transacción, que no tengan evento de disparo definido, siguiendo el orden de dependencias determinado por GeneXus (así como las fórmulas asociadas al primer nivel). A modo de ejemplo, se disparará la regla: “Default( InvoiceDate, &Today);”Después de ejecutadas las reglas mencionadas para el cabezal, se ejecutarán todas las reglas que tengan como evento de disparo BeforeValidate, ya que inmediatamente después ocurrirá la acción de validación (o confirmación) de la información de ese primer nivel.

Inmediatamente después de la validación del primer nivel se ejecutan las reglas asociadas al primer nivel de la transacción que incluyan en su definición el evento de disparo AfterValidate, o los BeforeInsert, BeforeUpdate, BeforeDelete, dependiendo del modo en el que se esté.

Por ejemplo: Si no podemos autonumerar las facturas con la propiedad Autonumber por no ser soportada por el DBMS elegido:

InvoiceId = PGetNumber.udp(‘INVOICE’) on BeforeInsert;

Page 137: Aplicaciones Genexus

131

Seguidamente a la ejecución de las reglas asociadas al primer nivel con alguno de estos eventos de disparo se ejecuta la acción de grabación; es decir, se grabará físicamente la instancia correspondiente al primer nivel de la transacción como registro físico en la tabla correspondiente (en este ejemplo, en la tabla: INVOICE).Inmediatamente después de haberse grabado esa instancia:

· si la grabación correspondió a una inserción: se ejecutarán las reglas asociadas al primer nivel de la transacción con evento de disparo AfterInsert.· si la grabación correspondió a una actualización: se ejecutarán las reglas asociadas al primer nivel de la transacción con evento de disparo AfterUpdate.· si la grabación correspondió a una eliminación: se ejecutarán las reglas asociadas al primer nivel de la transacción con evento de disparo AfterDelete.

Si se trata de una transacción de dos niveles, como en este caso, a continuación se ejecutará para cada una de las líneas:

En primer lugar, las reglas asociadas al segundo nivel de la transacción que no tengan evento de disparo definido, siguiendo el orden de dependencias determinado por GeneXus (así como las fórmulas asociadas al segundo nivel). Ejemplos de ello son la regla

Subtract( InvoiceDetailQuantity, ProductStock );

la fórmula

InvoiceDetailAmount = InvoiceDetailQuantity*ProductPrice.

Después de ejecutadas las reglas mencionadas para una línea, se ejecutarán todas las reglas que tengan como evento de disparo BeforeValidate, dado que inmediatamente después ocurre la validación de la línea; esto es una acción que ocurre a continuación de haber terminado de trabajar con la línea.

Inmediatamente después de la validación de la línea, se ejecutarán las reglas asociadas al segundo nivel de la transacción que incluyan en su definición alguno de los eventos de disparo: AfterValidate, BeforeInsert, BeforeUpdate, BeforeDelete.

Seguidamente a la ejecución de las reglas asociadas al segundo nivel con alguno de estos eventos de disparo se ejecutará la acción de grabación; es decir, se grabará físicamente la instancia correspondiente a la línea como registro físico en la tabla correspondiente (en este ejemplo, en la tabla: INVOICEDETAIL).

Inmediatamente después de haberse grabado la instancia correspondiente a la línea como registro físico en la tabla correspondiente:

• si la grabación correspondió a una inserción: se ejecutarán las reglas asociadas al segundo nivel de la transacción con evento de disparo AfterInsert.• si la grabación correspondió a una actualización: se ejecutarán las reglas asociadas al segundo nivel de la transacción con evento de disparo AfterUpdate.• si la grabación correspondió a una eliminación: se ejecutarán las reglas asociadas al segundo nivel de la transacción con evento de disparo AfterDelete.

Todas estas operaciones sombreadas de gris claro, se ejecutarán en el orden descrito, para cada una de las líneas.Luego de la iteración de todas las líneas, podemos suponer la existencia de una acción que podríamos llamar abandono del segundo nivel. Luego de la misma se ejecutarán las reglas definidas con evento de disparo AfterLevel Level Atributo del 2do nivel. Si no existe otro nivel, como es el caso del ejemplo, entonces coincidirá con el evento de disparo BeforeComplete.

Page 138: Aplicaciones Genexus

132

Aclaración importante: Todas las operaciones sombreadas, tanto en gris claro como en gris oscuro, se ejecutan únicamente si se trata de una transacción de dos niveles; de modo que cuando se trata de una transacción de un nivel, tales operaciones no se ejecutarán. El motivo de los dos sombreados distintos, es para diferenciar el conjunto de operaciones que se ejecuta para cada una de las líneas (sombreado gris claro) de las operaciones que se ejecutan solamente una vez finalizada la iteración en las líneas (sombreado gris más oscuro). A continuación seguimos explicando en orden, el resto de las operaciones que se ejecutan, así sea que se trate de una transacción de un nivel o dos.

Luego de haberse ejecutado todas las operaciones explicadas hasta el momento, se efectuará un commit,

A continuación se ejecutarán las reglas con evento de disparo AfterComplete.

Es de fundamental importancia que quede claro que todas las operaciones explicadas se ejecutarán en el orden en el que se han descrito, para cada factura con la cual se trabaje por medio de la transacción "Invoice" (ya sea que se ingrese, modifique o elimine).

Puede ser útil tener en cuenta que se han resaltado en negrita las acciones cada vez que se las ha mencionado. Las mismas son: validación, grabación , abandono del segundo nivel y commit.

Es indispensable asimilar el orden en el que se ejecutan las reglas en una transacción, cuáles son los eventos de disparo disponibles para asignarles, cuándo se disparan exactamente, y qué acciones ocurren antes y después de cada evento de disparo, ya que solamente conociéndolos bien se podrá programar el comportamiento de las transacciones adecuadamente. Es sencillo comprender que si necesitamos programar determinados controles o acciones en las transacciones, tendremos que saber bien si hacerlo antes de que se grabe el cabezal, después de que se haya grabado el mismo, para cada una de las líneas después de que se hayan grabado, o antes, después del commit o antes, por lo tanto es fundamental tener claro todo este tema.

Page 139: Aplicaciones Genexus

133

Ejemplos¿Cuándo se dispararán las siguientes reglas?

• Something.call( InvoiceId ) if Insert;

• Something.call( InvoiceId ) on BeforeInsert;

• Something.call( InvoiceId, ProductId ) on BeforeInsert;

• Something.call( InvoiceId ) on BeforeInsert Level ProductId;

Luego de validado el campo InvoiceId e inferido que se está en modo Insert

Luego de disparadas todas las reglas y fórmulas según árbol, y validados todos los datos del cabezal. Un instante antes de insertar el registro.

Luego de disparadas todas las reglas y fórmulas según árbol, y validados todos los datos de la línea. Un instante antes de insertar el registro.

Ídem que el anterior. Observar que Level ProductId especifica que se estáhablando del BeforeInsert de las líneas y no del cabezal.

Page 140: Aplicaciones Genexus

134

Ejemplos

Algunas reglas están mal programadas. ¿Cuáles?

• InvoiceDate = &today on AfterInsert;

• Something.call( InvoiceDate ) on AfterInsert;

• Something.call( InvoiceId, ProductId ) on AfterLevel Level ProductId;

Incorrecto: El último momento para asignar valor a un atributo del cabezal es inmediatamente antes de su grabación (BeforeInsert)

Correcto: aquí se está pasando el valor de un atributo del cabezal; mientras se esté en la instancia de la factura se tiene ese valor en memoria. Último momento posible para utilizarlo AfterComplete.

Incorrecto: la regla, sin el evento de disparo está asociada al 2do. Nivel, es decir, se dispararía por cada línea. Pero el evento de disparo la condiciona a ejecutarse al salir de las líneas. ¿Qué valor tendría ProductId?

Page 141: Aplicaciones Genexus

135

Reglas con el mismo evento de disparo

• Son disparadas en el orden en que fueron definidas

• Ejemplo 1‘xxx’.call() On AfterComplete;‘yyy’.call() On AfterComplete;

• Ejemplo 2‘pgmname’.call( CustomerId, &flag) On AfterComplete;error(' ') if &flag = 'N’ On AfterComplete;

Reglas con el mismo evento de disparoCuando en una transacción se definen dos o más reglas con el mismo evento de disparo, y no existe ninguna dependencia entre ellas, las mismas se ejecutarán respetando el orden de definición.

Ejemplos:1) Se definen las siguientes reglas en una transacción:

‘xxx’.Call() on AfterComplete;‘yyy’.Call() on AfterComplete;

Como las dos reglas definidas están condicionadas con el mismo evento de disparo, y no existe ninguna dependencia entre ellas, las mismas se ejecutarán en el mismo orden en el cual se han escrito.

2) En una transacción se necesita invocar a un procedimiento que realiza determinada validación y retorna un valor ‘S’ o ‘N’; si el valor devuelto es ‘N’, se debe dar un mensaje de error.

Para resolver esto, evaluaremos dos posibilidades:

2.1) Definir las reglas:PXXX.call(CustomerId, &flag) on AfterComplete;error(‘…’) if &flag=‘N’ on AfterComplete;

2.2) O definir las reglas:&flag = PXXX.udp(CustomerId) on AfterComplete;error(‘…’) if &flag=‘N’ on AfterComplete;

Page 142: Aplicaciones Genexus

136

En la primera alternativa, se ha definido una regla call y una regla error. Ambas reglas tienen el mismo evento de disparo, y aparentemente existiría dependencia entre ellas, ya que la regla de error estácondicionada al valor de la variable &flag, y la variable &flag se pasa por parámetro en la regla call.

Sin embargo, si bien la dependencia nos puede parecer evidente porque en el procedimiento programaremos a la variable &flag, de salida, en la sección de reglas de la transacción -que es donde se encuentran las reglas que estamos viendo-, el especificador de GeneXus no puede saber si los parámetros pasados en un call son de entrada, de salida, o de entrada-salida; en consecuencia el especificador no encontraráinterdependencia entre las reglas call y error, ya que la variable &flag podría ser pasada como variable de entrada al procedimiento, y en ese caso por ejemplo, no habría una dependencia por la cual primero se deba ejecutar la regla call y luego la regla error.

Así que concluyendo, no se detectan dependencias entre las reglas call y error de la alternativa 2.1), por lo que las mismas se dispararán entonces en el orden en el que estén escritas. Es importante ver que si las reglas call y error estuvieran escritas en orden inverso (es decir, primero la regla error y después la reglacall), el comportamiento no será el esperado en muchos casos.

Con respecto a la segunda alternativa, observemos que la misma consiste en una regla con udp y una reglaerror. Ambas reglas tienen el mismo evento de disparo, y en este caso sí existe dependencia entre ellas, ya que la regla error está condicionada al valor de la variable &flag, y como la invocación al procedimiento se realiza con udp, para el especificador de GeneXus queda claro que la variable &flag vuelve modificada del procedimiento; por lo tanto el especificador de GeneXus entiende que primero se debe disparar la invocación al procedimiento con udp y luego la regla error, porque la variable &flag se carga mediante la invocación al procedimiento con udp, y luego de que dicha variable tenga valor, es que habrá que evaluar si disparar la regla error, o no.

En el caso 2.2) entonces, independientemente del orden de definición de ambas reglas, la invocación al procedimiento con udp se disparará primero, y luego de ello, se disparará la regla error (en caso de que se cumpla la condición de disparo, claro está).

Por esta razón se recomienda que siempre que se quieran definir validaciones de este tipo, se utilice udp en lugar de call.

Page 143: Aplicaciones Genexus

137

Eventos en Transacciones

En las transacciones se permite la programación dirigida por eventos, que es un estilo de programación en el cuál se define código que permanece ocioso, hasta que suceden eventos provocados por el usuario o por el sistema, que provocan que el código definido se ejecute.

Los eventos son acciones reconocidas por un objeto que pueden suceder o no. A cada evento se le puede asociar código, que se ejecutará solamente si el evento se produce.

El código que se le puede asociar a un evento se escribe siguiendo el estilo procedural; y cuando el evento se produce, el código asociado al mismo se ejecutará secuencialmente.

Page 144: Aplicaciones Genexus

138

Eventos en Transacciones

• Evento Start

• Evento ‘User Event’

• Evento After Trn

• Evento Exit

• Evento TrackContext

Como en Web no se mantiene un estado en el servidor que permita saber qué es lo que se ejecutó en el cliente, no es posible saber si se está ingresando la primera instancia de una factura, o si es la n-ésima. Por esta razón, se disparará el evento Start cada vez que se envíe al servidor la información de la instancia con la que se esté trabajando.

En cuanto al evento Exit, se ejecutará por cada iteración, al final de la misma.

El evento TrackContext apunta a obtener interfaces de usuario sensibles al contexto. Programando este evento se podrá recibir información del contexto para luego tomar las decisiones necesarias.

Page 145: Aplicaciones Genexus

139

Eventos Start

• Start: Se ejecuta cada vez que se  somete el  form de una transacción al servidor.

Event Startcódigo

EndEvent

EJEMPLO: Event Start&entrada=Now()

EndEvent

SINTAXIS:

El evento Start es un evento del sistema, por lo tanto ocurre automáticamente.

EJEMPLO:En una transacción nos interesa capturar la fecha y hora de entrada a la misma. Para ello en el evento Start le asignamos a una variable de nombre &entrada y tipo de datos DateTime, el resultado de la función Now() que devuelve la fecha y hora actual:

Event Start&entrada = Now()

EndEvent

Se ejecutará cada vez que se someta el form de la transacción, es decir cuando se presione cualquier botón del form.

Notas generales:En el evento Start fundamentalmente se trabaja con variables. En cuanto a utilizar atributos en este evento, ya sea para evaluarlos y/o usarlos de algún modo menos para actualizarlos, se debe tener en cuenta que los únicos atributos que se tienen disponibles son los que se reciben por parámetro en la regla parm. Ningún otro atributo tendrá valor en este evento, pues todavía no se ha editado ninguna instancia de la transacción.

Page 146: Aplicaciones Genexus

140

Eventos de Usuario

• Además de los eventos ofrecidos por GeneXus, el analista puede definir eventos creados por él, llamados eventos de usuario.

Web: Orden de ejecución

1. Evento Start2. Lectura de atributos y variables del form3. Evento de usuario seleccionado

Propiedades

Como se puede observar en la sintaxis, se le debe dar un nombre a un evento de usuario, debiéndose declarar a continuación de la palabra Event, encerrado entre comillas simples.

EJEMPLO:Se desea que en la transacción "Invoice", el usuario tenga la posibilidad de imprimir la factura con la cual estétrabajando, presionando el botón:

Event ‘Print Invoice’ //evento definido en la transacción "Invoice"PrintInvoice.Call( InvoiceId )

EndEvent

¿Cómo asociar un evento de usuario a un control?Además de los botones, también las imágenes y los text blocks admiten la asociación de evento de usuario. Para realizar la asociación se debe insertar el control correspondiente en el form Web y luego en las propiedades del control, se deberá seleccionar donde dice OnClickEvent uno de los eventos existentes, o se puede crear uno nuevo. Volveremos sobre este tema en el capítulo de Web Panels.

Page 147: Aplicaciones Genexus

141

Evento After Trn

• Ocurre inmediatamente después de la ejecución de las reglas con evento de disparo AfterComplete.

• Sintaxis:

• Ejemplo: Event After trnReturn

EndEvent

Event After Trn código

Endevent

El evento After Trn de las transacciones ocurre inmediatamente después de la ejecución de las reglas con evento de disparo AfterComplete. Por consiguiente, el código que se incluya en este evento se ejecutaráluego de culminada cada iteración completa por medio de la transacción (es decir, luego de haberse grabado cada cabezal con sus correspondientes líneas como registros físicos en las tablas que corresponda y de haberse efectuado COMMIT).

Existen las siguientes alternativas para programar comportamientos que se deseen ejecutar luego de cada iteración completa por medio de una transacción:

1. Definir reglas individuales con evento de disparo AfterComplete y dejar el evento After Trn sin código2. Definir todas las sentencias en el evento After Trn con estilo procedural, y no definir reglas con evento de disparo AfterComplete3. Definir ambas cosas: algunas reglas con evento de disparo AfterComplete y código en el evento After Trn

Como venimos explicando, primero se ejecutan las reglas definidas con evento de disparo AfterComplete, e inmediatamente después de las mismas se ejecuta el código definido en el evento After Trn.

Un concepto que es muy importante tener claro es que tanto en reglas con evento de disparo AfterCompletecomo en el evento After Trn, se conocen los valores de los atributos del primer nivel de la transacción.

Es decir, si bien ya se grabaron físicamente los registros correspondientes al cabezal y las líneas de cierta iteración completa, e incluso se efectuó COMMIT, aún se tienen disponibles los valores de los atributos del primer nivel, pudiendo estos utilizarse para pasarlos por parámetro en una invocación, o evaluar su valor, o usarlos de algún modo salvo actualizarlos1.---------------------------------------------------------------------------------------------------------------------------------------------------------------1 Hay dos motivos por los cuales no es posible actualizar atributos en reglas con evento de disparo AfterComplete ni en el evento After Trn. El primer motivo es que ya se han hecho las grabaciones correspondientes e incluso se ha efectuado COMMIT, de modo que ya es tarde para asignar valores a atributos. Y además, en lo que respecta al evento After Trn, en los eventos no se permite realizar asignaciones a atributos.

Page 148: Aplicaciones Genexus

142

No se permite asignar valores a atributos en los eventos.

Los valores de los atributos pueden modificarse en las transacciones:· haciéndolo el usuario final, en tiempo de ejecución, a través del form (sólo atributos de las tablas bases asociadas a la transacción, o aquellos de la extendida permitidos por regla update)· mediante reglas definidas por el programador (atributos de las tablas bases asociadas a la transacción y sus extendidas)

Solemos decir que los eventos Start y Exit son sin tabla base. Con esta expresión nos referimos a que en los eventos Start y Exit no hay consulta activa a la base de datos (ya que en el evento Start aún no se ha hecho la consulta y en el evento Exit se está cerrando la instancia y ya no disponemos de la consulta). Por este motivo es que no se conocen valores de atributos en los eventos Start y Exit, salvo los recibidos por parámetro.

Por el contrario solemos decir que los eventos After Trn y de usuario son con tabla base, ya que cuando los mismos se ejecutan, sí hay una consulta en edición. Entonces, en particular en el evento After Trn, se conocen los valores de los atributos del primer nivel (el segundo nivel ya se ha iterado a esa altura y no hay posibilidad de posicionamiento en alguna línea en particular); y en lo que respecta a los eventos de usuario se disponen los atributos de todos los niveles 1.

Es fundamental comprender que así se disponga de los valores de ciertos atributos u otros dependiendo del evento, los mismos podrán utilizarse para ser evaluados y/o pasados por parámetro a objetos que se invoquen, y/o para alguna otra operación cualquiera que no sea asignarles valor.

Concluyendo, en ningún evento (no sólo de transacciones, sino de ningún objeto GeneXus) se permite realizar asignaciones a atributos.

---------------------------------------------------------------------------------------------------------------------------------------------------------------1 Si en un evento de usuario se referencian atributos de un segundo nivel u otro nivel subordinado, cuando el evento de usuario se ejecute se tendrán en cuenta los atributos de aquella línea en la que se esté posicionado; al momento de ejecutarse el evento de usuario se considerarán los valores de los atributos de dicha línea. Y si el usuario no se había posicionado explícitamente en determinada línea, por defecto la línea que estará seleccionada será la primera, así que se considerarán los valores de los atributos de la misma.

Page 149: Aplicaciones Genexus
Page 150: Aplicaciones Genexus

143

Integridad Transaccional

IT

Page 151: Aplicaciones Genexus

144

¿Qué es el concepto: integridad transaccional?

• Un  conjunto  de  actualizaciones  a  la  base  de  datos  tiene integridad transaccional cuando en caso de una  finalización “anormal”,  la  base  de  datos  permanece  en  estado consistente.

Muchos manejadores de bases de datos (DBMSs) cuentan con sistemas de recuperación ante fallos, que permiten dejar la base de datos en estado consistente cuando ocurren imprevistos tales como apagones o caídas del sistema.

Page 152: Aplicaciones Genexus

145

• Una  unidad  de  trabajo  lógica  (UTL) es  un  conjunto  de operaciones  a  la  base  de  datos,  que  deben  ejecutarse  o  bien todas o bien ninguna de ellas.

¿Qué es el concepto: unidad de trabajo lógica (UTL)?

Los manejadores de bases de datos (DBMSs) que ofrecen integridad transaccional permiten establecer unidades de trabajo lógicas (UTLs), que corresponden ni más ni menos que al concepto de transacciones de base de datos.

Page 153: Aplicaciones Genexus

146

¿Qué es efectuar COMMIT?

• El comando COMMIT permite especificar que cierto conjunto de operaciones realizadas  sobre  una  base  de  datos,  ha  culminado  de  efectuarse correctamente:

...........Operación sobre Base de DatosOperación sobre Base de DatosFinaliza UTLComienza UTLOperación sobre Base de DatosOperación sobre Base de DatosOperación sobre Base de DatosOperación sobre Base de DatosFinaliza UTL

• De modo que efectuar COMMIT en una base de datos, significa que se da por finalizada una unidad de trabajo lógica (UTL).

COMMIT

COMMIT

Podemos ver que una unidad de trabajo lógica (UTL) queda definida por el conjunto de operaciones entre un par de Commits.

Page 154: Aplicaciones Genexus

147

¿Qué es efectuar ROLLBACK?

• Hacer ROLLBACK (vuelta a atrás) provoca que se deshagan todas  las operaciones efectuadas en  la base de datos que no hayan quedado con COMMIT. 

• Esto  se  resuelve  deshaciendo  todas  las  operaciones posteriores al último COMMIT.

Page 155: Aplicaciones Genexus

148

Unidad de trabajo lógica (UTL)por defecto en GeneXus

Todo objeto GeneXus transacción y todo objeto GeneXus procedimiento, determina unidades de trabajo lógicas (UTL).

Es decir, las transacciones y procedimientos son los únicos objetos GeneXus (*) que permiten actualizar la base de datos, y por defecto GeneXus incluye en los programas generados asociados a los mismos, la sentencia COMMIT.

En el objeto procedimiento GeneXus incluye un COMMIT automático al final del Source.

En el objeto transacción GeneXus incluye un COMMIT automático al final de cada instancia, inmediatamente antes de las reglas con evento de disparo AfterComplete

(*) una excepción la brindan los Business Components, pero no realizan commitautomáticamente.

Es importante aclarar que GeneXus incluye la sentencia COMMIT en los programas generados asociados a transacciones y procedimientos, sólo en ambientes de trabajo Cliente/Servidor (incluyendo, por tanto, los ambientes Web). El motivo de esto es que en ambientes Cliente/Servidor existe un DBMS que asegura la integridad transaccional, por lo tanto GeneXus efectúa la tarea de definir las unidades de trabajo lógicas (UTLs).

¿Dónde incluye GeneXus COMMIT exactamente?

En cada procedimiento: al final del programa fuente.

En cada transacción: inmediatamente antes de las reglas con evento de disparo AfterComplete (E inmediatamente después de las BeforeComplete). Es decir, que por cada iteración completa que se efectúe en tiempo de ejecución por medio de la transacción, habrá un COMMIT, justo antes de las reglas con evento de disparo AfterComplete.

Nota: El tipo de datos Business Component que veremos más adelante permite actualizar la base de datos desde cualquier objeto GeneXus, pero también como veremos, no realiza automáticamente un COMMIT.

Page 156: Aplicaciones Genexus

149

• Propiedad Commit on Exit de transacciones y procedimientos:

Valores:

• Yes (Default): Se ejecuta COMMIT

• No: No se ejecuta COMMIT

Personalización de UTL en GeneXus

GeneXus ofrece una propiedad a nivel de cada objeto transacción y procedimiento, para definir si se desea que su programa generado efectúe COMMIT, o no. El nombre de la propiedad es Commit onExit y su valor por defecto es Yes (por eso, toda transacción y procedimiento por defecto efectúa COMMIT).

Si se desea que cierta transacción o procedimiento no tenga en su programa generado COMMIT, bastará con cambiar el valor de la propiedad Commit on Exit a No.

Page 157: Aplicaciones Genexus

150

Trn. “X”

Commit on Exit = No

Proc. “Y”

• Ejemplo de uso de Commit on Exit = No

call

Importante: invocar desde la Trn. “X” al Proc. ”Y” utilizando un evento de disparo que consideremos adecuado y que ocurra antes de la ejecución del COMMIT de la Trn “X”.

Commit on Exit = Yes

Personalización de UTL en GeneXus

¿Por qué motivo se puede necesitar no efectuar COMMIT en una transacción o procedimiento?Para personalizar una unidad de trabajo lógica (UTL). Es decir, podemos necesitar ampliar una unidad de trabajo lógica (UTL) para que varias transacciones1 y/o procedimientos, conformen una única unidad de trabajo lógica (UTL).

Ejemplo (mostrado arriba):

La transacción “X” invoca al procedimiento “Y”, y se desea que ambos objetos conformen una única UTL. La transacción actualiza ciertos registros, y el procedimiento otros, y se desea que ese conjunto total de operaciones conforme una única UTL (para asegurarnos de que si ocurre una falla, quede efectuado el conjunto completo de actualizaciones a la base de datos, o nada).

Para lograrlo podemos eliminar el COMMIT del procedimiento y dejar que se realice en la transacción (al retornar del procedimiento a la transacción, para que se ejecute al final de todas las operaciones); de modo que configuraríamos la propiedad Commit on Exit del procedimiento con valor: No y dejaríamos la propiedad Commit on Exit de la transacción con el valor por defecto: Yes. Pero además de esto, es fundamental que la invocación al procedimiento se realice antes de que se ejecute el COMMIT en la transacción (ya que la idea es que ambos objetos conformen una única UTL, y para ello el COMMIT debe efectuarse en la transacción al retornar del procedimiento); así que la invocación al procedimiento deberá definirse en la transacción, con un evento de disparo que ocurra antes de la ejecución del COMMIT (dependiendo de si la transacción es de un nivel o más, y de los requerimientos, podría servir AfterInsert por ejemplo, AfterUpdate, o AfterLevel Level Atributo del 2do nivel, o BeforeComplete, pero no AfterComplete).

No existe una única solución para personalizar una UTL. Lo fundamental es analizar cuál objeto puede hacer COMMIT (pudiendo haber más de una posibilidad) y una vez que se decida cuál objeto efectuará COMMIT, las invocaciones que se requieran hacer, deberán efectuarse en momentos adecuados, considerando si ya se efectuó el COMMIT o no.

-----------------------------------------------------------------------------------------------------------1 En ambiente Web existe una importante restricción a este respecto: si desde una transacción se invoca a otra, el Commit que realice una no aplica sobre los registros ingresados/modificados/eliminados por la otra. Es decir, el Commit de cada transacción solo tiene “visibilidad” sobre los registros operados por esa transacción, y no por la otra, por lo que dos transacciones distintas no pueden quedar incluidas en una misma UTL. No puede realizarse personalización en este caso.

Page 158: Aplicaciones Genexus

151

Por ejemplo, para que la transacción y procedimiento vistos conformen una única UTL, podríamos haber optado también por la alternativa de que no efectúe COMMIT la transacción (Commit on Exit = No), sino que lo haga el procedimiento al final de todo; y de hacerlo así, no sería un error –como sí lo sería en la solución anterior-invocar al procedimiento utilizando el evento de disparo AfterComplete, porque la transacción no hará COMMIT, sino que lo hará el procedimiento.

Concluyendo, es cuestión de decidir cuál objeto hará COMMIT y que las invocaciones que se deban hacer, se hagan en momentos adecuados, para que la UTL personalizada quede bien definida.

Otro ejemplo:Sea la transacción “Invoice” estudiada hasta el momento. Supongamos que no modificamos el valor predeterminado de la propiedad Commit on Exit.Supongamos ahora que el usuario ejecuta la transacción, ingresando la factura 1 con todas sus líneas. Luego pasa a ingresar la factura 2 y cuando está ingresando la 3era. línea de la misma, ocurre un apagón. Al recuperarse la energía y reiniciarse la ejecución, ¿qué registros habrán quedado grabados en las tablas y cuáles se habrán perdido?

La factura 1 íntegra estará grabada (cabezal y sus líneas). ¿Por qué? Pues porque al terminar de ingresarla y pasar a ingresar la factura 2, se efectuó un Commit. La factura 2 con los registros que se habían grabado hasta el momento de la falla de energía, se habrá perdido. ¿Por qué? Pues porque la transacción realiza el rollback de todo lo que se hubiere efectuado luego del último Commit. El cabezal de la factura 2 y las 2 líneas que se habían ingresado no estaban “commiteadas” aún.

Observar entonces que el Commit no es por transacción entera (es decir, todas las iteraciones del cabezal y sus líneas) sino por cada instancia de cabezal + líneas.Si el Commit se realizara una única vez antes de cerrar la transacción, entonces si se hubieran ingresado 29 facturas y a la trigésima se cayera el sistema, se perderían las 29 facturas anteriores (se desharía todo, ya que aún no se habría alcanzado el Commit). Esto no es así, y si ocurriera una caída del sistema a la trigésima factura ingresada, las 29 anteriores quedarán grabadas (no así la trigésima).

Page 159: Aplicaciones Genexus

152

Trn.“X”

• No puede definirse una UTL compuesta por varias transacciones Web.

call

Personalización de UTL

• Una transacción Web solo puede Commitear los registros insertados por ella misma, o por procedimientos en una cadena de invocaciones, pero no puede Commitear los registros insertados por otra transacción.

Trn.”Y”

Trn.“X”call

(luego del

Commit)

Trn.”Y” Proc.”Z”call

(antes del

Commit)

UTL

No pueden quedar dentro de una misma UTL

UTL 1 UTL 2

En ambiente Web los registros “visibles” para ser commiteados por una transacción son los actualizados por la propia transacción, y por los procedimientos que ésta invoque antes de su Commit, pero no los de otra transacción.

Cada transacción trabaja, así, sobre UTLs distintas.

Es por ello que en el primer ejemplo presentado arriba, donde la transacción “X” llama a la transacción “Y” luego de haber insertado un registro, aunque la transacción “Y” realice un Commit al final de que cabezal y líneas sean ingresados, este Commit no valdrá sobre el registro que había sido ingresado previamente por la transacción “X”. Este registro quedará “perdido”, sin Commit.

Por la forma de trabajo en Internet, las transacciones Web “viven” solamente el tiempo entre que el usuario de un navegador selecciona el link o presiona un botón y la nueva página es mostrada. Toda modificación a la base de datos que se haga durante la “vida” de la transacción debe ser confirmada o eliminada antes de que la Transacción Web termine su ejecución y retorne la página resultante.

Como consecuencia, una Transacción Web inicia una UTL (unidad de trabajo lógica) al comenzar a ejecutar y la cierra (ya sea por COMMIT o ROLLBACK) antes de terminar. No puede formar parte de otra UTL. Si un programa llama a una Transacción Web, ésta iniciará otra (nueva) UTL.

En cambio no sucede lo mismo con los procedimientos. En el segundo ejemplo mostrado arriba, vemos que podemos formar una UTL que engloba a la transacción “Y” y al procedimiento “Z”… sin embargo no podemos incluir a la transacción “X” en la misma UTL.

Page 160: Aplicaciones Genexus

153

• Si deseamos que las inserciones mediante dos transacciones distintas conformen una única UTL:

Tenemos una solución: utilizar Business Components y el comando Commit al terminar de insertar mediante las variables Business Components los registros asociados a ambas transacciones (se verá más adelante).

Personalización de UTL

Trn.“X” Trn.”Y”

Si se necesita que las operaciones de dos o más transacciones (con o sin procedimientos incluidos) conformen una misma UTL, se pueden emular las transacciones con Web panels y Business Components y utilizar el comando Commit.

Dejamos aquí anotado simplemente el tema, para volver a él luego de estudiados los Business Components, donde nos será posible comprender esta solución.

Page 161: Aplicaciones Genexus

154

• GeneXus ofrece los comandos: COMMIT y ROLLBACK

• Se  pueden  incluir  en  Procedimientos,  Web  Panels,  asícomo en combinación con Business Components.

• Ejemplo  (usuario  final  decide  si  ejecutar  Commit o Rollback): Se  invoca  desde  una  transacción  a  varios procedimientos  consecutivos,  se  les  configura  a  todos ellos  la propiedad Commit on exit = No… y en el último procedimiento  se  le  pregunta  al  usuario  si  confirma; dependiendo  de  la  respuesta  del  usuario,  habrá que ejecutar el comando COMMIT o ROLLBACK

Comandos COMMIT y ROLLBACK de GeneXus

Page 162: Aplicaciones Genexus
Page 163: Aplicaciones Genexus

155

Objeto Procedimiento

Page 164: Aplicaciones Genexus

156

Procedimientos

Definición

• Procesos no interactivos de consulta y actualización de la base de datos.

Procedimientos:Definen procesos no interactivos de consulta y actualización de la base de datos. Los procedimientos pueden generar un archivo formato PDF, mediante el cual es posible listar información por pantalla o impresora. Además, los procedimientos pueden actualizar la base de datos1.

--------------------------------------------------------------------------------------------------------------------------------1 Como veremos más adelante, existe un tipo de datos especial, que no es estrictamente un tipo de datos, sino algo un poco más complejo, el business component, por medio del cuál se podrán realizar actualizaciones a la base de datos en cualquier objeto GeneXus. Por tanto, utilizando variables de tipo de datos business component, podrán realizarse actualizaciones incluso en los objetos que por naturaleza no ofrecen esta posibilidad, como los web panels.

Page 165: Aplicaciones Genexus

157

Características

• Definición procedural. 

• Definición sobre la base de conocimiento.

• Independencia de la base de datos: definición a nivel de atributos.

Definición proceduralA diferencia de las reglas de las transacciones donde las especificaciones se realizan en forma declarativa y GeneXus determina en el momento de generar el programa la secuencia de ejecución, en los los procedimientos las especificaciones se realizan en forma procedural. De esta forma, la secuencia de ejecución es determinada por el analista, utilizando para ello un lenguaje bastante simple que contiene comandos de control, de impresión, de acceso a la base de datos, etc.

Definición sobre la base de conocimientoLa gran potencia del lenguaje de los procedimientos radica en que las definiciones se hacen sobre la base de conocimiento y no directamente sobre el modelo físico (tablas, índices, etc.). Esto nos permite utilizar automáticamente todo el conocimiento ya incorporado o generado por GeneXus a partir de las especificaciones realizadas.Por ejemplo, si deseamos desplegar el resultado de una fórmula alcanza con nombrar al atributo fórmula en el lugar adecuado y GeneXus disparará su cálculo desplegando el resultado, sin necesidad de que el analista tenga que brindar ninguna otra información. La información de cómo se calcula un atributo fórmula está contenida en la base de conocimiento.También podremos utilizar el concepto de tabla extendida, ya que GeneXus conoce las relaciones entre las tablas de la base de datos, por lo que el analista no necesita explicitar estas relaciones a la hora de recuperar datos.

Independencia de la base de datos: definición a nivel de atributosLa definición de los procedimientos se hace a nivel de atributos: no es necesario indicar explícitamente cuáles tablas serán recorridas ni mediante qué índices. Con solo mencionar los atributos a los que se desea acceder es suficiente para que GeneXus determine esta información. Esto es posible porque GeneXus tiene un completo conocimiento de la estructura de la base de datos.De esta manera logramos una real independencia de la base de datos, ya que cualquier cambio en las tablas será manejado automáticamente por GeneXus y de esta forma, para actualizar los programas alcanzará, gran parte de las veces, con regenerar los objetos sin tener que modificar nada de lo programado en ellos.

Page 166: Aplicaciones Genexus

158

Elementos

• Como en las transacciones, pueden definirse variables que serán locales al objeto.

Para cada procedimiento se puede definir:

• Source: Aquí se escribe el código correspondiente a la lógica del procedimiento. También pueden definirse al final del código subrutinas1 que podrán ser invocadas desde el propio código mediante el comando adecuado.

• Layout: Así como las transacciones tienen una pantalla (form), los procedimientos tienen un “layout” de la salida. En esta sección se define la presentación del procedimiento: los datos que se quieren listar y el formato de la salida.

• Rules: permiten definir cierto comportamiento particular, como los parámetros que recibe el objeto, si el procedimiento implementará un listado pdf, etc.

• Conditions: Condiciones que deben cumplir los datos para ser recuperados (filtros).

• Variables: Variables locales al objeto (ídem que con el objeto transacción)

• Help: Permite la inclusión de texto de ayuda, para ser consultado por los usuarios en tiempo de ejecución, para el uso del procedimiento. Se puede redactar una ayuda para cada lenguaje.

• Documentation: Permite la inclusión de texto técnico, de tipo wiki, para ser utilizado como documentación del sistema.

• Propiedades: Definen aspectos generales del procedimiento, como su nombre, descripción, tipo de salida (impresora, archivo, pantalla). Recordemos que alcanza con presionar F4 para obtener las propiedades.

--------------------------------------------------------------------------------------------------------------------------------1 No se tratarán en el presente curso.

Page 167: Aplicaciones Genexus

159

Ejemplo

área con datos fijos

área con datos fijos

área con datos variables (acceso a la base de datos)

• Queremos implementar un listado como el que sigue:

Por ejemplo, supongamos que queremos implementar un procedimiento para imprimir el identificador, nombre y país de todos nuestros clientes y queremos que el listado luzca como se muestra en la figura.

Para ello, debemos identificar en la salida del listado las distintas áreas que lo componen. A cada una de ellas la representaremos con un Printblock.

Los primeros dos Printblocks lucirán en GeneXus tal cuál las primeras dos áreas señaladas pues éstas contienen únicamente textos, líneas, recuadros. También podríamos haber fusionado estas dos áreas convirtiéndolas en una y utilizando por tanto un único Printblock.

El tercer Printblock será el correspondiente al área de datos variables de la figura anterior, que representa información que debe ser extraída de la base de datos.Lo que queremos mostrar en este caso es el identificador y nombre de cada cliente, junto con el nombre del país al que pertenece. Esta información es la representada por los atributos CustomerId, CustomerName y CountryName de la base de conocimiento de la aplicación, por lo que el tercer Printblock contendrá los tres controles atributo CustomerId, CustomerName y CountryName.

Transformando las áreas en Printblocks, el Layout del procedimiento nos quedará como el que figura en la página siguiente.

Page 168: Aplicaciones Genexus

160

Printblock

Layout

• Sucesión de Printblocks.• No importa el orden de definición.• Cada Printblock debe tener un nombre único.• Solo se declaran, son invocados desde el Source con el comando “print” (Ej.: print header).

Nombre de cada Printblock

El Layout de un procedimiento será una sucesión de Printblocks que no tienen por qué seguir el orden en el que se desea que aparezcan en la salida.

En el ejemplo anterior, el mismo procedimiento habría sido impreso si se hubieran especificado los Printblocks en el orden inverso (o en cualquier orden).

Aquí simplemente se declaran. El orden en el que se ejecutan queda determinado en la sección Source que es la que contiene la lógica del procedimiento. Desde allí serán invocados mediante un comando específico para tal fin (el comando print).

Por esta razón, cada Printblock deberá tener un nombre único para poder ser referenciado luego desde el Source.

En el ejemplo, para listar todos los clientes, el Printblock de nombre “customer” deberá ser invocado dentro de una estructura repetitiva en el Source. Esta estructura repetitiva es el comando For each que estudiaremos luego.

Page 169: Aplicaciones Genexus

161

Layout: Printblock

• Para definir los Printblocks tenemos los siguientes controles disponibles:

• y para insertar un Printblock damos botón derechosobre el layout y elegimos Insert Printblock.

El Printblock es un tipo de control válido solamente en los procedimientos, que es insertado y eliminado del Layout por el analista, y que contendrá otros controles -atributos, textos, recuadros, líneas, etc.-, siendo estos últimos los que efectivamente especifican qué es lo que se quiere desplegar en la salida.

Para insertar los controles en el Form de una transacción contábamos con una toolbox. La misma toolbox se utiliza para insertar los controles en el Layout. De hecho esta toolbox está disponible para todos los objetos GeneXus que se creen, y en cada caso tendrá los controles disponibles según el tipo de objeto.

Para insertar un Printblock damos botón derecho en cualquier lugar del layout y seleccionamos InsertPrintblock.

Como todo control, el Printblock tiene propiedades que pueden ser configuradas por el usuario. En particular, tiene la propiedad “Name”, muy importante dado que es el identificador del Printblock. Con este identificador es que el Printblock puede ser invocado desde el Source para ser impreso.

Para acceder a la propiedades de un Printblock, lo seleccionamos y presionamos F4 o View/Properties.

Page 170: Aplicaciones Genexus

162

Source• Define la lógica del procedimiento mediante programación 

procedural

• Lenguaje muy simple

• Comandos usuales de control:  If, Do‐case, Do‐while, For

• Comandos de impresión:  Print, Header, Footer

• Comando de acceso y actualización de la BD:  For each, New, Delete

• Comandos para salir de un bucle, abandonar el programa, invocar a otro objeto, invocar a una subrutina, etc.:  Exit, Return, Call, Do

En esta sección se define la lógica del procedimiento.

El lenguaje que se utiliza para programar el código fuente de los procedimientos es muy simple, y consta de algunos comandos que iremos viendo.

El estilo de programación es procedural –imperativo– por lo que el Source será una sucesión de comandos para los que el orden es fundamental: el orden en el que estén especificados corresponderá, salvo excepciones, al orden en el que serán ejecutados.

Existen, como en todo lenguaje imperativo, comandos de control para la ejecución condicional (if, do case), la repetitiva (do while, for), para invocar a otro objeto (call), para cortar las iteraciones dentro de un bucle (exit) o abandonar el programa (return), así como también comandos específicos de este lenguaje: para imprimir un Printblock del Layout (print), para acceder a la base de datos (For each), para insertar nuevos registros en una tabla (new), para invocar a una subrutina (do), etc.

Al final de la sucesión de comandos que constituye el código general o principal del procedimiento, pueden definirse subrutinas que podrán ser invocadas (mediante el comando do) desde el código general. No pueden ser invocadas desde otro objeto (son locales).

Por su importancia, empezaremos estudiando en profundidad el comando de acceso a la base de datos, fundamental a la hora de recuperar la información almacenada. Luego se tratarán brevemente los comandos de control, que son comunes a todos los lenguajes de programación imperativa, los comandos de asignación y los de impresión.

Page 171: Aplicaciones Genexus

163

Comando For each

• Se utiliza para acceder a la información de la base de datos.

• Con un For each se recorre una tabla de la base de datos: la tabla base del For each.

• Para cada registro de esa tabla, se quiere hacer algo con la información asociada. (Ejemplo: imprimirla)

• Todo comando For each termina con un Endfor.

La definición del acceso a la base de datos para recuperación de información se realiza con un único comando: el comando For each1.

Usando el For each se define la información a la que se va a acceder. La forma de hacerlo se basa en nombrar los atributos a utilizar.

Así, con este comando se definen qué atributos se necesitan y en qué orden se van a recuperar, y GeneXus se encarga de encontrar cómo hacerlo. No se especifica de qué tablas se deben obtener, ni qué índices se deben utilizar para acceder a esas tablas: eso lo inferirá GeneXus. Evidentemente esto no siempre es posible, y en tales casos GeneXus da una serie de mensajes de error indicando por quéno se pueden relacionar los atributos involucrados.

La razón por la cuál no se hace referencia al modelo físico de datos es porque de esta manera la especificación del procedimiento es del más alto nivel posible, de tal forma que ante cambios en la estructura de la base de datos la especificación del mismo se mantenga válida la mayor parte de las veces.

Cuando aparece un For each se está indicando que se quiere recuperar información de la base de datos. Concretamente GeneXus sabe que con un For each se quiere recorrer (o navegar) una tabla. Para cada registro de esa tabla, se quiere hacer algo con la información asociada (ej: imprimirla).

Por lo tanto, todo comando For each tendrá una tabla física asociada: la tabla que será recorrida o navegada. A esta tabla la llamaremos tabla base del For each.

----------------------------------------------------------------------------------------------------------------------------------1 Cuando estudiemos los business components veremos que utilizando su método Load también se consigue consultar la base de datos.

Page 172: Aplicaciones Genexus

164

Comando For each

• Ejemplo: Listado de clientes

• Layout:

• Source:

CUSTOMER COUNTRY

For eachprint customer

Endfor

Intuitivamente resulta claro que con este comando estamos queriendo listar identificador, nombre y país de cada uno de los clientes de la base de datos. Es decir, queremos que se recorra la tabla CUSTOMER, y para cada cliente se recupere de la tabla COUNTRY el nombre del país al que pertenece, imprimiendo esta información, junto con el identificador y nombre del cliente. (Observar que la tabla COUNTRY pertenece a la extendida de CUSTOMER)

¿Cómo infiere esto GeneXus si todo lo que hicimos en el For each del ejemplo fue nombrar los atributos que nos interesaba mostrar?

Page 173: Aplicaciones Genexus

165

Comando For each

• Tabla que se recorre: CUSTOMER

• Tabla que se accede para cada cliente: COUNTRY

• INTERPRETACIÓN:

CUSTOMER COUNTRY

For each record in CUSTOMER tableFind the corresponding CountryName in table COUNTRY

print customerEndfor

Dentro de todo For each se navega -recorre o itera- la tabla base, pero puede accederse a las tablas que constituyen su tabla extendida para recuperar información, que por pertenecer a la extendida estará unívocamente relacionada con cada registro de la tabla base con el que se estétrabajando en cada iteración (el concepto de tabla extendida es muy importante en este comando y sugerimos repasar su definición).

Es por ello que en el For each del ejemplo, la tabla base será CUSTOMER, y además se accederá“para cada” cliente, no solo a los datos de su registro, sino a los del registro asociado en la tabla COUNTRY (que está en la extendida de CUSTOMER). Decimos entonces que se recorreCUSTOMER y se accede además a COUNTRY para buscar el resto de la información requerida.

Como podemos ver claramente en el ejemplo presentado, no le damos explícitamente a GeneXusesta información. No es necesario, ya que GeneXus conoce las relaciones entre las tablas, y en base a los atributos mencionados dentro del For each, puede encontrar sin necesidad de más información una tabla extendida que los contenga.

La tabla base de esa extendida es la que elige como tabla base del For each.

Page 174: Aplicaciones Genexus

166

Comando For each: determinación de tabla base

• El acceso a la base de datos queda  determinado por los atributos que son utilizados dentro del comando For each. 

• Para ese conjunto de atributos, GeneXus buscará la mínima tabla extendida que los contenga. 

• Su tabla base será la tabla base del For each.

A la tabla base correspondiente a esa tabla extendida la llamaremos tabla base del For each y serárecorrida en forma secuencial, ejecutando para cada registro lo que se indique en los comandos internos al For each.

Page 175: Aplicaciones Genexus

167

Comando For each: determinación de tabla base

{CustomerId, CustomerName, CountryName} ⊂ ext(CUSTOMER)

{CustomerId, CustomerName, CountryName} ⊂ ext(INVOICE)

Pero:ext(CUSTOMER) < ext(INVOICE)

ext(CUSTOMER) es la mínimatabla extendida que contiene a los atributos del For each.

Tabla base: CUSTOMER

Para el ejemplo presentado en el que se quieren listar de cada uno de los clientes su identificador, nombre y nombre de país, si observamos los atributos utilizados dentro del For each, vemos que ellos son los contenidos en el Printblock de nombre “customer”: CustomerId, CustomerName y CountryName.

¿En qué tablas están estos atributos?

• CustomerId está en 2 tablas:- CUSTOMER como clave primaria (PK).- INVOICE como clave foránea (FK).

• CustomerName está solo en CUSTOMER (es un atributo secundario).

• CountryName está solo en COUNTRY (es un atributo secundario).

GeneXus conoce las relaciones entre las tablas. Podemos ver el diagrama correspondiente a las tablas en las cuales aparecen los atributos del For each (Tools/Diagrams).

Aquí puede verse claramente el por qué del requerimiento de que la tabla extendida sea la mínima (entendiendo por mínima aquella que involucra menor cantidad de tablas). La tabla extendida de INVOICE también contiene a todos los atributos del For each, pero no es mínima, pues la de CUSTOMER también los contiene.

Por lo tanto, se va a recorrer secuencialmente la tabla CUSTOMER, y para cada registro de esa tabla, se va a acceder a la tabla COUNTRY, para recuperar el registro de la misma que cumpla: COUNTRY.CountryId = CUSTOMER.CountryId y para el mismo se va a recuperar el valor del atributo CountryName, para poder imprimirlo, junto con el código y nombre del cliente.

Page 176: Aplicaciones Genexus

168

Listado de navegación

tabla base

tabla base: la que se navega

Se accede para recuperar inforelacionada (CountryName)

Se resuelve la consulta ordenadapor la PK de la tabla base

Listado de navegación

GeneXus ofrece para todos sus objetos un listado conocido como listado de navegación, que es el resultado de la especificación del objeto. Este listado es muy útil para los procedimientos, ya que indica cuáles son las tablas que se están accediendo en cada For each del Source, si existe un índice para recuperar los datos de la tabla base, y en caso de que así sea cuál es ese índice (su nombre), si se aplican filtros sobre los datos o se van a listar todos, etc.

De esta manera, el analista no tiene que ejecutar el objeto para verificar que la lógica sea la esperada. Con estudiar el listado de navegación ya tiene la información necesaria para saber si se está recorriendo la tabla esperada, si se están aplicando correctamente los filtros deseados, etc.

Como puede verse en el listado correspondiente al procedimiento del ejemplo, muestra para el comando For each del Source, cuál es su tabla base, por qué orden se va a resolver esa consulta (será el orden en el que se imprimirán los resultados), si existe un índice que satisfaga ese orden cuál es su nombre, y además aparecen dos elementos más: los filtros de navegación y el diagrama de tablas.

Los filtros de la navegación indican qué rango de la tabla base se va a a recorrer. En el ejemplo se va a recorrer toda la tabla base del For each: empezando por el primer registro de CUSTOMER, y hasta que se alcance el fin de tabla (utilizando el índice ICUSTOMER).

También se muestra en un pequeño diagrama de tablas, la tabla base del For each con su clave primaria, e indentadas todas las tablas de la extendida que deban accederse para recuperar información asociada al registro de la tabla base con el que se esté trabajando en cada iteración del For each. En este caso se muestra solamente la tabla COUNTRY.

En el comando For each del ejemplo no aparece explícitamente ninguna información respecto al orden en el que queremos que se imprima la información. En este caso GeneXus elige como orden la clave primaria de la tabla base del For each. Es por esta razón que para el For each del ejemplo GeneXus determinó que el orden será el correspondiente al atributo CustomerId, clave primaria de la tabla CUSTOMER.

Page 177: Aplicaciones Genexus

169

For each: cláusulas Where

• Permiten establecer filtros sobre los datos a recuperar. Ejemplo:

• Solo para los registros que cumplan las condiciones booleanas de las cláusulas where deben ejecutarse los comandos internos al For each.

• Las cláusulas where aplican sólo si se satisfacen las condiciones de sus cláusulas when.

For eachwhere CustomerName >= &Start when not &Start.IsEmpty()where CustomerName <= &End when not &End.IsEmpty()

print customerEndfor

Para restringir los datos que se quieren listar en un For each se utilizan las cláusulas where del comando.

Si en el listado de clientes no queremos listar todos los clientes, sino solo aquellos cuyo nombre estédentro de un rango ingresado por el usuario, entonces debemos agregar al For each que habíamos visto una clálusula where, para especificar los filtros deseados sobre los datos:

For eachwhere (CustomerName >= &Start) and (CustomerName <= &End)

print customerEndfor

donde las variables &Start y &End deben definirse en el procedimiento con el mismo tipo de datos que CustomerName, y cargarse con valores fijos ó recibidos por parámetro1.

Con la cláusula where definida le estamos diciendo a GeneXus que no queremos quedarnos con todos los registros de la tabla base, sino solo con aquellos para los que se satisfaga la condición booleana de la cláusula.

En el ejemplo escribimos una sola cláusula where con una condición compuesta, pero podríamos haber programado lo mismo con dos cláusulas where, como se muestra arriba en la transparencia.

Es decir, cuando aparecen varios “where” la condición de filtro que se va a aplicar sobre los datos es la conjunción booleana de todas las condiciones de los “where” que aparezcan.

Observemos que en la transparencia las cláusulas where están a su vez condicionadas con claúsulas when. Esto se lee de la siguiente forma: se aplicará el filtro establecido por el where solo cuando se satisfaga la condición del when.

En el ejemplo, solo se aplicará el primer filtro: “CustomerName >= &Start” si la variable &Start no estávacía. Si está vacía, este filtro no se aplicará. Análogo es el caso de la segunda cláusula when. Observar que si &Start y &End están vacíos, no aplicará ninguna de las cláusulas where, y por tanto se listarán todos los clientes (como si las cláusulas where no hubiesen sido escritas).

Cada condición booleana de un “where” puede estar compuesta de varias expresiones booleanas concatenadas con los operadores lógicos and, or y not.

--------------------------------------------------------------------------------------------------------------------------------------------------1 A través de un objeto que los pide al usuario, por ejemplo un Web Panel.

Page 178: Aplicaciones Genexus

170

Listado de navegación

Listado de navegación

Aparece un nuevo elemento en este listado que no estaba presente antes, cuando no teníamos cláusulas where: las constraints (restricciones).

¿Qué información nos brinda este listado de navegación?

• que la tabla base del For each seguirá siendo CUSTOMER

• que se seguirá ordenando la consulta por CustomerId, utilizando el índice ICUSTOMER correspondiente

• que seguirá recorriendo toda la tabla CUSTOMER en busca de la información

•pero que para cada cliente evaluará si cumple con las restricciones que aparecen enumeradas (CustomerName>= &Start si &Start no está vacía y CustomerName<=&End si &End no está vacía) y solo en caso de que las cumpla, ejecutará para ese cliente los comandos que aparecen dentro del For each. En este caso, imprimirá los valores de los atributos del Printblock “customer”: CustomerId, CustomerName, CountryName.

• que debe acceder a la tabla COUNTRY cuya clave primaria es CountryId para obtener algún dato (CountryName)

Page 179: Aplicaciones Genexus

171

For each: cláusulas Where

• Atributos permitidos: los de la tabla extendida de la tabla basedel For each

Ejemplo:

For eachwhere CountryName = ‘Uruguay’

print customerEndfor

Los atributos utilizados en las condiciones de filtro pueden ser cualesquiera de la tabla extendida del For each.

En el ejemplo, si bien la tabla base del For each es CUSTOMER, estamos filtrando los datos a recuperar utilizando el atributo CountryName, que es de la tabla COUNTRY, perteneciente a la extendida de CUSTOMER.

En este ejemplo tampoco se explicita nada con respecto al orden, por lo cuál los datos aparecerán ordenados por la clave primaria de la tabla base, es decir, por identificador de cliente, CustomerId.

Page 180: Aplicaciones Genexus

172

For each: cláusula Order• Permite establecer el orden en el que se quieren recuperar los 

datos. Ejemplos:

• Para determinar orden descendente se deben colocar paréntesis rodeando a los atributos del orden. Ej: order (CustomerName)

For each order CustomerNameprint customer

Endfor

For eachorder CustomerName when not (&Start.IsEmpty() and &End.IsEmpty())

print customerEndfor

Si queremos realizar un listado de todos los clientes pero ordenado por nombre del cliente en lugar de por código, lo único que tenemos que hacer es modificar el comando For each agregando esta información del orden.

Esto se logra utilizando la cláusula order del For each, como se muestra en el primer ejemplo.

Como no existe un índice definido en la tabla CUSTOMER por el atributo CustomerName, GeneXusindicará en el listado de navegación mediante una advertencia (“warning”) que no existe un índice para satisfacer el orden, lo que podría ocasionar problemas de performance, dependiendo de la plataforma de implementación elegida, de la cantidad de registros que deben ser leídos de la tabla, etc.

En ambientes cliente/servidor, si no existe índice para satisfacer el orden, el For each se traduce en una consulta SQL (“select”) que es resuelta por el motor del DBMS de la plataforma.

Al igual que en el caso de las cláusulas where, la cláusula order puede condicionarse, como se muestra en el segundo ejemplo. En caso de no cumplirse la condición del when, no aplicará ese orden y de no existir orden incondicional (sin cláusula when) como en el ejemplo, el orden a utilizar será indefinido, significando esto que el orden resultante podrá variar de DBMS a DBMS e incluso entre ejecuciones sucesivas.

Pueden especificarse varias cláusulas order condicionadas (con cláusula when) consecutivas y una sin condición (la última de la lista). La primera cláusula order cuya condición del when se satisfaga, será la elegida y su orden el utilizado.

Cláusula Order None: cláusula que evita que GeneXus elija por defecto el orden de los atributos de la clave primaria de la tabla base y utilice un orden de navegación indefinido.Si se utiliza la cláusula Order None, GeneXus entiende que no desea establecer ningún orden de recorrida en particular y delega esta tarea al DBMS.La cláusula order none admite condición para aplicarse (when).

Page 181: Aplicaciones Genexus

173

Listado de navegación

For each order CustomerNameprint customer

Endfor

Listado de navegación

Cuando no existe índice que satisfaga el orden de un For each, como es el caso del ejemplo, el analista GeneXus puede resolver crearlo (índice de usuario). En la mayoría de los casos el procedimiento será bastante más eficiente de esta manera, pero se debe mantener un índice más (lo que implica mayor almacenamiento y mayor procesamiento para mantener actualizado el índice)

No es posible recomendar a priori cuál de las dos soluciones es la mejor (no índice vs índice de usuario), por lo tanto se debe estudiar, caso por caso, la solución particular teniendo en cuenta la plataforma de implementación y siendo fundamental la frecuencia con que se ejecutará el procedimiento. De cualquier manera, si al comienzo no se definió el índice de usuario y posteriormente se decide definirlo, alcanza con regenerar el procedimiento (sin modificar nada de lo programado en el mismo) y éste pasará a utilizarlo.

El listado de navegación anterior nos informa que:

• la tabla base del For each es CUSTOMER• y se recorrerá ordenada por CustomerName• no existe un índice definido para ese atributo• se recorrerá toda la tabla CUSTOMER con el orden especificado• no hay condiciones de filtro, por lo que para todos los registros de la tabla se ejecutarán los comandos dentro del For each (en nuestro caso, el comando print).

Page 182: Aplicaciones Genexus

174

Si nos interesa filtrar los clientes de forma tal que sus nombres pertenezcan a un rango, en el primer ejemplo, como no especificamos cláusula order GeneXus ordena por clave primaria, es decir, por CustomerId.

En este caso, el listado de navegación nos va a informar que se debe recorrer toda la tabla CUSTOMER, y para cada registro de la misma se debe evaluar si el registro cumple o no con las condiciones (restricciones o “constraints”). En caso afirmativo, se imprimen para el mismo los datos correspondientes.

Si en lugar de ordenar los datos por CustomerId pedimos que se ordenen por CustomerName, como se presenta en el segundo ejemplo, la tabla base se recorre ordenada por CustomerName y como en los filtros establecemos que queremos quedarnos solo con aquellos clientes cuyo nombre, CustomerName, esté en el rango determinado, entonces ¡ya no será necesario recorrer toda la tabla base para obtener los datos que cumplen con las condiciones!

Diremos que esta segunda consulta está optimizada en ese sentido. Tener en cuenta, sin embargo, que GeneXus no tiene creado un índice en forma automática por CustomerName, y aquí habrá que evaluar si conviene crear un índice de usuario (que debe ser mantenido por Genexus luego) o no crear índice y que se cree un índice temporal en ejecución para resolver la consulta si el DBMS no puede resolverlo de otra forma.

El listado de navegación nos informará si una consulta está o no optimizada, de acuerdo a si recorrerá toda la tabla (desde “First Record” hasta “End of table”) o si recorrerá por el contrario un rango más reducido.

OPTIMIZACIÓN: Orden compatible con los filtros

For each order CustomerNamewhere CustomerName >= &Startwhere CustomerName <= &End

print customerEndfor

For eachwhere CustomerName >= &Startwhere CustomerName <= &End

print customerEndfor

No se recorre todala tabla base:¡optimizado!

Se recorre todala tabla base

Page 183: Aplicaciones Genexus

175

El listado de navegación nos informa que la consulta está optimizada ya que recorre solamente los registros incluidos en el filtro (desde CustomerName>=&Start hasta CustomerName <=&End).

Para determinar el orden se tiene en cuenta:

•Los atributos de la cláusula Order especificada por el usuario •Las restricciones que aplican al nivel (atributos mencionados en la regla Parm del procedimiento, condiciones explícitas tanto en el Where como en las Conditions) •La existencia de índices sobre estos atributos.

Distinguimos 2 casos:

1) Se escribe una cláusula order

• El For each quedará ordenado por esos atributos, exista o no un índice por éstos. • Si no existe un índice con los atributos del order, pero existen condiciones implícitas o condiciones explícitas por igualdad, se busca si existe un índice que contenga los atributos de las condiciones más los del Order. La condición explícita prevalece sobre la ímplícita para la determinación del Order, en caso que sean diferentes y exista índice por cada una de ellas. • Si existe un índice, los atributos de las condiciones serán agregados en la lista del Orderpara que dicho índice sea considerado en su lugar.

2) No se escribe cláusula order

• En este caso, si existe algún índice por los atributos de la condición, el Order quedarádeterminado por los atributos del índice.• Si no existe un índice que corresponda con las condiciones, o sea que no se puede optimizar la recorrida según las condiciones del nivel, entonces se ordenará por los atributos de la Primary Key.

OPTIMIZACIÓN: Orden compatible con los filtros

GeneXus siempre intentaráencontrar el mejor orden posible para que la consulta sea optimizable, es decir, coincida con algún índice definido en la base de datos.

Page 184: Aplicaciones Genexus

176

Por ejemplo, si tenemos las transacciones:

COUNTRY CITY{ {

CountryId* CountryId*} CityId*

}

El For each:

For Each order CityIdWhere CountryId = 1

...Endfor

Recorrerá la tabla CITY, ordenando por: CountryId, CityId y utilizando el índice ICITY (índice porclave primaria que contiene ambos atributos).

Aunque es el propio DBMS el que resuelve el plan de acceso más apropiado, la información antes mencionada influirá en su determinación.

Page 185: Aplicaciones Genexus

177

For each: cláusula Defined by

• No ofrece funcionalidad alguna en lo que respecta a los datos a recuperar.

• Se utiliza exclusivamente para dar un elemento más para la determinación de la tabla base del For each deseada.

For eachdefined by InvoiceDate

print customerEndfor

Ejemplo: Mín. extendida que contiene a InvoiceDate, CustomerId, CustomerName, CountryName:

ext(INVOICE) tabla base INVOICE

Puede darse el caso de que para un For each haya más de una tabla base cuya extendida contenga a los atributos del For each, siendo mínima. Ante esta ambigüedad, GeneXus escoge la “primera” de estas tablas extendidas mínimas.

Para resolver este tipo de ambigüedad surge la cláusula defined by, que permite nombrar atributos de la tabla base deseada, que no se utilizarán para devolver la consulta ordenada por esos atributos, ni para filtrar la información a recuperar, ni para ser desplegados en el listado (es decir, no tienen funcionalidad alguna con respecto a los datos a recuperar), sino solo para aportar más información que permita determinar la tabla base del For each.

En la cláusula Defined by se debe hacer referencia a por lo menos un atributo de la tabla base deseada.

De la misma manera, se puede (y se suele) utilizar para modificar la que sería la tabla base en caso de no nombrarse ningún atributo más dentro del For each. Este es el caso del ejemplo presentado, en el que no queremos listar todos los clientes de la tabla CUSTOMER, sino por el contrario, queremos listar todos los clientes de las facturas. De no nombrarse dentro del For each algún atributo de INVOICE, la tabla base sería CUSTOMER.

En la mayoría de los casos no es necesario utilizar esta cláusula. Sin embargo, para procedimientos más o menos complejos, aún cuando no exista problema de ambigüedad, se recomienda el uso del Defined by porque mejora bastante el tiempo de especificación del procedimiento. Sin embargo, no puede aconsejarse un uso indiscriminado. La contra de utilizar esta cláusula cuando no es necesaria es que ata un poco más el código al diseño de las tablas.

Supóngase por ejemplo que no se tiene creada una tabla COUNTRY, y se tiene de cada cliente el país al que pertenece, como atributo secundario. Si lo que queremos es listar los clientes y su país, serían equivalentes:

For each For eachDefined by CountryName

print customer print customerEndfor Endfor

donde customer es un Printblock con los atributos CustomerId, CustomerName y CountryName.Si ahora decide crearse la tabla COUNTRY y tener en la transacción “Customer” a CountryId como FK, si bien el primer For each continuará siendo válido y haciendo lo que queremos, el segundo dejará de funcionar, ya que en el Defined By no hay ningún atributo de la tabla base.

Page 186: Aplicaciones Genexus

178

• Atributos permitidos: pueden aparecer varios atributos de la tabla extendida, pero al menos uno debe corresponder a la tabla base que se desea (en caso contrario dará un error).

• Se sugiere utilizar atributos secundarios, dado que los mismos están en una única tabla del modelo y esto evita ambigüedades.

For each: cláusula Defined by

Pueden aparecer varios atributos, para el posible caso en el que no alcance uno solo para determinar completamente la tabla base deseada, donde al menos uno de ellos deberá estar asociado a la tabla base deseada.

Se recomienda el uso en el Defined by de atributos secundarios de la tabla base que se desea navegar, ya que como sabemos, los atributos secundarios solo pueden estar en una tabla del modelo y de esta forma eliminamos por completo toda posible ambigüedad.

Esto sin embargo, no es obligatorio, es decir, pueden nombrarse en el Defined by atributos primarios cuando se sepa que no habrá ambigüedad en la elección de la tabla base.

Un error común es creer que cuando un For each tiene esta cláusula, la tabla base del mismo queda determinada exclusivamente a partir de los atributos mencionados en el defined by.

La realidad es que los atributos del defined by arrojan una o más tablas base candidatas a ser la tabla base del For each, pero luego hay que ver si tomando cada tabla base candidata, su extendida contiene a todos los demás atributos del For each, además de los del defined by.

Si ninguna de las posibles tablas base candidatas cumplen esta condición, entonces el procedimiento dará un error al ser especificado, y no podrá ser generado (recordemos que debe cumplirse que todos los atributos del For each estén contenidos en una misma tabla extendida).

Page 187: Aplicaciones Genexus

179

For each: cláusula When none

• Permite ejecutar determinado código cuando en un For each no se encuentra ningún registro que cumpla las condiciones.

• Ejemplo:For eachwhere CustomerName >= &Startwhere CustomerName <= &End

print customerWhen none

print messageEndfor

El Printblock message (que podrá contener un texto advirtiendo al usuario de que no existen clientes que cumplan los filtros) se ejecuta sólo cuando no se entra en el For each, es decir, cuando no hay ningún registro correspondiente a la tabla base del For each para el que se cumplan las condiciones de filtro.

También se aplica a For each [selected] line, XFor Each y XFor First, comandos que veremos más adelante.

La cláusula When none debe ser la última dentro del For each. Las acciones a realizar cuando no existe ningún registro para el que se cumplan las condiciones, quedan determinadas por el bloque de código que hay entre la cláusula When none del For each y el Endfor.

Cuando un For each no tiene condiciones de filtro, los comandos del When none se ejecutarán solo en el caso en que se cumpla que la tabla base del For each esté vacía, porque solo en ese caso no habrá ningún registro que cumpla las condiciones de filtro.

Importante:

• Si aparecen atributos en el bloque de código correspondiente al When none, éstos no son tenidos en cuenta para determinar la tabla base del For each.

• Si se incluyen For eachs dentro del When none no se infieren Joins ni filtros de ningún tipo con respecto al For each que contiene el When none, ya que son considerados For eachs paralelos.

Page 188: Aplicaciones Genexus

180

Comando For each - Sintaxis

For each[{[order] order_attributesi [when condi]}... | [order none] [when

condx]][using DataSelectorName([[parm1 [,parm2 [, ...] ])][{where {conditioni when condi} |{attribute IN DataSelectorName([[parm1 [,parm2 [, ...] ]} }...]

[defined by defined_attributes][Blocking NumericExpression]

code1[when duplicate

code2][When none

code3]Endfor

La sintaxis presentada generaliza el ejemplo con el que vinimos trabajando.

Order order_attributes::= att1, …, attnEs una lista de atributos, que indican el orden en el que será devuelta la consulta, siendo atti un atributo de la base de conocimiento escrito simple, o entre paréntesis curvos. Cuando un atributo del order aparece rodeado de paréntesis curvos se está indicando orden descendente para el mismo.

Pueden mencionarse atributos de la tabla extendida.

Es posible definir varias cláusulas order condicionales, y una incondicional, que debería ser la última listada. El por qué responde al hecho de que como solamente una de esas cláusulas ordertomará efecto, se van evaluando sus condiciones (las del when) hasta la primera que de True, y con esa se queda. Si ninguna da true y existe una cláusula incondicional (es decir, sin when), se tomaráese orden. Si no existe tal cláusula, el orden será indefinido, queriendo esto significar que dependerá de la plataforma, e incluso podrá variar entre ejecuciones sucesivas. La justificación para escribir cláusulas order condicionales, deriva de si queremos aplicar cláusulas where condicionales. Es decir, por motivos de optimización de las consultas.

Por ejemplo, si queremos filtrar por CustomerName > &Name when not &Name.IsEmpty(), entonces para optimizar la consulta deberíamos ordenar por CustomerName, pero si no se va a aplicar el filtro, dado que &Name está vacía, entonces será mejor dejar un orden indefinido.Para ello especificamos la cláusula order condicional:

order CustomerName when not &Name.IsEmpty()

En lugar de todo lo anterior, también puede especificarse una cláusula order none que se agrega para cuando no nos interesa un orden en particular y queremos que éste quede indefinido.

Page 189: Aplicaciones Genexus

181

Elección del índice: GeneXus elige automáticamente el índice a utilizar para satisfacer el orden. GeneXus siempre intentará encontrar el mejor orden posible para que la consulta sea optimizable, es decir, coincida con algún índice definido en la base de datos. Para determinar el orden se tiene en cuenta:

• Los atributos de la cláusula Order especificada por el usuario • Las restricciones que aplican al nivel (atributos mencionados en la regla Parm del procedimiento, condiciones explícitas tanto en el Where como en las Conditions) • La existencia de índices sobre estos atributos.

Aunque es el propio DBMS el que resuelve el plan de acceso más apropiado, la información antes mencionada influirá en su determinación.

Los atributos del order son tenidos en cuenta a la hora de determinar la tabla base del For each. Pero ellos por sísolos no la determinan. Deben examinarse también otras partes del For each.

Using DataSelectorNamePermite definir filtros acorde al criterio definido en el DataSelector1 definido en DataSelectorName.

Where ConditionCondición booleana que deberán cumplir los datos para ser procesados dentro del For each, pudiendo ser una condición compuesta, utilizando los operadores lógicos and, or y not.

Los atributos que aparezcan en la condición booleana pueden ser tanto de la tabla base del For each como de la extendida.

Como se desprende de la sintaxis, para un mismo For each pueden especificarse n cláusulas where sucesivas, cada una con una condición:where cond1where cond2...where condn

La ocurrencia de n cláusulas where es equivalente a la ocurrencia de una sola cláusula, con la conjunción booleanade las condiciones:

where cond1 and cond2 and … and condn

Los datos de la tabla extendida del For each que cumplan con todas las condiciones de los “where” serán los procesados en los comandos internos al For each (los del bloque de código code1).

Al igual que ocurre con la cláusula order, podrán condicionarse los filtros (con cláusulas when). De esta manera, primero se evalúa la cláusula when de cada cláusula where, y de cumplirse su condición, aplicarán el filtro especificado en el where.

Nota: Existe también la cláusula Option Distinct del For Each que permite retornar los registros que cumplan unicidad de valores de los atributos referenciados. No veremos esta cláusula. El lector interesado puede recurrir a las distintas fuentes de documentación para estudiarla (Help, Wiki)

-------------------------------------------------------------------------------------------------------------------------------------------------------------------1 El objeto DataSelector se verá más adelante en el curso.

Page 190: Aplicaciones Genexus

182

Defined bydefined_attributes::= att1, att2,…,attpEs un conjunto de atributos que serán utilizados a los solos efectos de determinar la tabla base del For each.

Al mencionar aquí algunos atributos de la tabla que se desea recorrer, éstos participarán en la determinación de la tabla base del For each.

La cláusula defined by aparece para solucionar algunos problemas de ambigüedad en la determinación de la tabla base (cuando existen varias tablas extendidas mínimas que contienen a los atributos del For each) o cuando se desea que la tabla base sea otra, distinta de la que sería determinada por los atributos que aparecen en el resto del For each (este caso cobrará sentido cuando se estudie “corte de control”). También se utiliza para mejorar el tiempo de especificación en procedimientos complejos.

Los atributos de esta cláusula no determinan por sí solos la tabla base del For each. Podría darse el caso de que de estos atributos surja determinada tabla como la candidata a tabla base, pero si luego el resto de los atributos del For each no están contenidos en la extendida de esa tabla, el For each dará un error y el objeto que lo contiene no podrá ser generado.

code1Es una sucesión de comandos en los que pueden utilizarse atributos de la tabla extendida del For each. A este bloque de código le llamaremos cuerpo del For each.

Los atributos que figuren en este bloque de código participarán en la determinación de la tabla base del For each.

Los comandos especificados se ejecutarán secuencialmente para los datos de la tabla extendida que cumplan las condiciones de filtro, considerándose los datos en el orden especificado.

BlockingSi bien se abordará este tema más adelante en el curso, a modo de idea general diremos que la especificación de esta cláusula permite realizar actualizaciones y eliminaciones en bloque, reduciendo así el número de accesos a la base de datos.

When DuplicateEsta cláusula solo tiene sentido en procedimientos (dado que tiene que ver con la actualización) y se verá más adelante.Se ejecutará esta cláusula si dentro del cuerpo del For each code1, se intenta actualizar un atributo que es clave candidata (tiene índice unique) y ya existe un registro con ese valor. GeneXus utiliza el índice unique para asegurar la unicidad de esa clave candidata y en caso de encontrar duplicados, si el For each tiene programada esta cláusula, ejecutará su código: code2 .De no existir la cláusula no se ejecutará código alguno.

When noneEn caso de que no existan datos que cumplan las condiciones de filtro no se ejecutarán los comandos del code1sino que se ejecutarán los del bloque de código code3.

Tanto para When Duplicate como para When none: Si se incluye dentro de alguno de los dos un comando Foreach, no se infieren joins ni filtros con respecto al For each que los contiene (el del When none | when duplicate). Son consideradas navegaciones independientes (la del code1, code2 y code3).

Page 191: Aplicaciones Genexus

183

Comando For each• Podemos hacer que GeneXus escriba el código base del For each

por nosotros, insertando “snippets” (con el menú Insert o desde la Toolbox):

Los “code snippets” son plantillas de código que GeneXus tiene predefinidas, que nos ayudan a escribir el código fuente. Cuando estamos trabajando en el Source de un procedimiento, la Toolboxnos muestra varios snippets que nos facilitan la escritura del comando For each.

Los snippets tienen a su vez un “atajo” (shorcut), que hacen que la escritura de código sea más rápida todavía. Por ejemplo, digitando simplemente “fe” se escribe automáticamente el siguiente código:

For each/*For each Code*/

Endfor

Luego el usuario sustituye la línea de comentarios con el código necesario.

La lista de los atajos de cada snippet, es la siguiente:

• fe (For each)• feu (For each using)• fen (For each When none)• feun (For each using When none)• few (For each where)• feuw (For each using where)• fewn (For each where When none)• feuwn (For each using where When none)

Page 192: Aplicaciones Genexus

184

For eachs paralelos

• Llamamos de esta forma al caso de For eachs que están escritos en forma secuencial  (no anidada) .  Ejemplo:

• También aplica al caso en el que un For each aparece dentro de la cláusula When none o when duplicate de otro. 

• Las navegaciones son totalmente independientes.

For eachprint invoice

EndforFor each

print billEndfor

El For each es un comando como otros, y por tanto puede aparecer varias veces dentro del Source, tanto en forma paralela (independiente), como anidado a otro For each.

Cuando dentro del cuerpo del For each (code1) aparece otro For each, decimos que se trata de Foreachs anidados. GeneXus soporta varios niveles de anidamiento para los For eachs.

El caso en el que un For each aparece en el bloque de código code3, si bien puede verse como un anidamiento de For eachs porque uno aparece dentro de otro, el comportamiento en cambio, es como el del caso de For eachs paralelos.

Un For each “anidado en el When none” de otro, solo se ejecutará si no existe ningún registro de la tabla base del For each que lo contiene que cumpla las condiciones de filtro.

En el ejemplo, “invoice” y “bill” son dos Printblocks del Layout que continen atributos de las tablas INVOICE y BILL (recibo) respectivamente.

Hemos definido dos For eachs paralelos. El primero recorrerá todas las facturas y el segundo todos los recibos.

Page 193: Aplicaciones Genexus

185

For eachs anidados

• Se busca recuperar por cada registro del For each principal, muchos registros del anidado

For each...For each

...Endfor...

When none...

Endfor

Cuerpo del For each principal

El For each es una estructura repetitiva que permite recuperar muchos registros de una tabla. Cuando uno piensa en For eachs anidados, es evidente que lo que se busca recuperar es, por cada registro del principal, muchos registros del anidado.

¿Qué cosas podría GeneXus detectar que se quiere hacer con este tipo de estructuras, de forma tal de poder inferir el comportamiento automáticamente con la menor codificación posible?

• para cada registro de una tabla recuperar algunos de otra: los relacionados.• para cada registro de una tabla recuperar todos los de otra.• procesar información por grupos, esto es, agrupar los registros de una tabla según el valor de un atributo o conjunto de atributos y para cada grupo, recuperar algunos registros: los correspondientes al grupo.

Siempre la relación es uno a muchos: por cada registro de una tabla recuperar muchos de la otra (pudiéndose tratar de la misma tabla).

Utilizando esta lógica es que GeneXus infiere las tablas base y el comportamiento de los For eachsanidados, sabiendo que lo que se desea es implementar alguna de las tres opciones anteriores.

Por ejemplo si queremos realizar un listado de todas las facturas del sistema, donde para cada una queremos imprimir también el detalle de la misma, debemos recorrer dos tablas: INVOICE (que almacena los cabezales) e INVOICEDETAIL (que almacena las líneas), y lo haremos de una forma bien simple, sin nombrar las tablas, y sin tener que explicitar todo, como veremos.

Otro ejemplo es el de un listado de todos los clientes, donde para cada uno se quieren imprimir, además de sus datos personales, los datos de todas sus facturas. Este comportamiento se logra con un par de For eachs anidados, donde el primero recorrerá la tabla CUSTOMER y el segundo recorrerá la tabla INVOICE, recuperando solo las facturas de ese cliente, como veremos en breve.

Page 194: Aplicaciones Genexus

186

For eachs anidados

• Ejemplo: imprimir todas las facturas con sus respectivas líneas

For eachprint invoice_headerFor each

print invoice_linesEndforprint invoice_amount

Endfor

{InvoiceId, InvoiceDate, CustomerName}

{ProductDescription, ProductPriceListPrice, InvoiceDetailQuantity, InvoiceDetailAmount}

{InvoiceAmount}

Queremos realizar un listado de todas las facturas del sistema, donde para cada una se muestre tanto información de su cabezal como de sus líneas.

En el Source programado, claramente recorremos la tabla INVOICE, imprimiendo los atributos que nos interesan del cabezal y para cada registro de esa tabla, recorremos la tabla INVOICEDETAIL, para imprimir los atributos que nos interesan de sus líneas.

¡Tan simple como eso! Otra vez, nos alcanza con nombrar los atributos que queremos utilizar y del resto se encarga GeneXus.

Observemos que ni siquiera tuvimos que especificar condición de filtro sobre los registros de INVOICEDETAIL a recuperar. GeneXus se da cuenta de la relación existente entre las tablas, y aplica automáticamente la condición de filtro sobre los datos, de manera tal de solo imprimir las líneas de “esa” factura (recordar que algo idéntico ocurría con las fórmulas verticales, como InvoiceAmount, donde la condición de filtro sobre los registros a ser sumados o contados quedaba implícita, y no había que especificarla).

Page 195: Aplicaciones Genexus

187

For eachs anidados

• Ejemplo: imprimir todas las facturas con sus respectivas líneas

INVOICE INVOICEDETAIL

Para cada registro de INVOICE imprimir algunos de sus datos (InvoiceId, InvoiceDate) y de su extendida (CustomerName). 

Luego navegar INVOICEDETAIL y recuperar los registros que correspondan a la factura que se está imprimiendo.

Los que cumplan la condición implícita:INVOICEDETAIL.InvoiceId = INVOICE.InvoiceId

Como para un For each simple, GeneXus debe determinar para cada For each (principal y anidado) cuál es su tabla base. Y luego, a partir de esa determinación, inferirá la lógica correspondiente.

Más adelante veremos con exactitud cómo es que GeneXus determina cada tabla base. Aquí nos quedaremos con la idea intuitiva de que lo hace en forma similar a como lo hacía para el caso de un For each simple.

Encuentra, pues, que debe recorrer las tablas INVOICE e INVOICEDETAIL.

Como esas tablas están relacionadas de acuerdo a una relación 1-N infiere más que eso: infiere además que debe aplicar la condición sobre los datos de INVOICEDETAIL que se indica arriba.

Page 196: Aplicaciones Genexus

188

For eachs anidados

• GeneXus debe:

• Determinar la tabla base de cada For each.

• A partir de eso definir las navegaciones que realizará para cada For each(existen 3 casos posibles). 

• La lógica de los For eachs dependerá de las relaciones que encuentre entre las tablas determinadas.

Cuando tenemos For eachs anidados, GeneXus debe determinar la tabla base de cada uno, y esas serán las tablas que se navegarán.

Para cada registro de la tabla base del For each principal, se ejecutarán los comandos del cuerpo del mismo. Entre esos comandos, se encuentra el For each interno, que se ejecutará, como cualquier otro comando, en el lugar donde se encuentre, realizando una navegación sobre su tabla base.

Pero para la determinación de la tabla base del For each anidado, podrá influir la tabla base del Foreach principal, por lo que las determinaciones no son por completo independientes, como podría pensarse.

A partir de la determinación de las tablas base de cada For each primero y de las relaciones que encuentre GeneXus entre las tablas involucradas luego, surgen tres posibles casos de For eachsanidados: join, producto cartesiano y corte de control, respectivamente.

Estudiaremos en lo que sigue cada uno de estos casos con ejemplos, para luego generalizar todo lo visto.

Page 197: Aplicaciones Genexus

189

For eachs anidados: determinación tablas base

Se procede en forma ordenada, determinandocada vez la tabla base de un nivel de anidación,yendo de afuera hacia adentro: primero sedetermina la tabla base del For each más externo, luego del que está anidado a éste y así sucesivamente.

Para cada For each, intervienen únicamentelos atributos propios de ese For each: delorder, where, defined by y todos los del cuerpo que no pertenezcan a un For each anidado (tampoco intervienen los de la cláusula When none).

For each...For each

...Endfor...

When none...

Endfor

Consideremos el caso más simple, de un par de For eachs anidados.

• La determinación de la tabla base del For each principal, es análoga al caso de For each simple (sin anidamientos). En este caso se consideran todos los atributos del For each principal, descartando los For eachs anidados que éste contenga (y todos sus atributos). GeneXus encuentra la mínima tabla extendida que contenga a los atributos referidos y define así la tabla base a través de la cual llega a todas las demás.

• Para determinar la tabla base del For each anidado, GeneXus se fija si los atributos utilizados dentro del cuerpo del mismo están incluidos o no dentro de la tabla extendida previamente determinada (la del For each principal). En caso afirmativo, GeneXus determina que la tabla base del For each anidado será la misma que la del For each principal. En caso contrario, se busca la mínima tabla extendida que cumpla que contiene a todos los atributos del For each anidado y que tenga alguna relación con la tabla base dell For each principal. La tabla base de dicha tabla extendida, será la tabla base del For each.

Si no puede encontrar una tabla extendida mínima que cumpla ambas condiciones, pero cumple que contenga a los atributos, finalmente la elige, pero siempre busca la forma de encontrar relaciones entre ambas tablas bases. Sólo en este último caso de que no se encuentran relaciones, se procede a determinar la tabla base como si se tratase de For eachs independientes.

Veremos un esquema resumiendo lo anterior más adelante.

Page 198: Aplicaciones Genexus

190

For eachs anidados: determinación tablas base

For eachprint invoice_headerFor each

print invoice_linesEndforprint invoice_amount

Endfor

{InvoiceId, InvoiceDate, CustomerName}

{InvoiceAmount}

Tabla base For each externo

For eachprint invoice_headerFor each

print invoice_linesEndforprint invoice_amount

Endfor

{ProductDescription, ProductPriceListPrice, InvoiceDetailQuantity, InvoiceDetailAmount}

Tabla base For each interno

INVOICE

INVOICEDETAIL

Para el ejemplo que presentamos antes, mostramos arriba cómo se determina cada tabla base.

Para la del anidado, como los atributos que figuran no están contenidos en la tabla extendida de INVOICE (que es la tabla base del principal), entonces se pasa a determinar su tabla base como se explicó anteriormente: se busca la tabla extendida mínima que contenga a ProductDescription, ProductPriceListPrice, InvoiceDetailQuantity e InvoiceDetailAmount, y que de ser posible estérelacionada con INVOICE.

La tabla que cumple ambos requisitos en INVOICEDETAIL.

Page 199: Aplicaciones Genexus

191

• Tablas base distintas 

• Tablas base iguales• Corte de Control: Corresponde al caso en el que queremos recuperar 

información por grupos.

Join: se recuperan algunos registros del anidado, los relacionados.

Producto cartesiano: se recuperan todos los registros del anidado.

For eachs anidados: lógica asociada

(Caso 1)

(Caso 2)

(Caso 3)

Fe externo

Fe anidado

¿

?

¿Existe relación implícita que lo vincule conun número N de registros del For each anidado?

No

1

N

De la determinación de las tablas base, surgen los tres casos de For eachs anidados que se mencionan y que estudiaremos uno a uno en lo sucesivo.

Este tema es de vital importancia, ya que la mayoría de las aplicaciones requieren navegaciones complejas sobre las tablas, donde se requiere una mixtura de todos estos casos.

Page 200: Aplicaciones Genexus

192

Caso 1: Join

• Distintas tablas base pero existe una relación 1‐N directa o indirecta entre ellas.

• Ejemplo: Listado de todos los clientes y sus facturas.

For eachprint customerFor each

print invoiceEndfor

Endfor

{CustomerId, CustomerName}

{InvoiceId, InvoiceDate,InvoiceAmount} INVOICE

CUSTOMER

CustomerId

En el For each anidado se ordena por atributo relación: CustomerId

ext(principal) ∩ base(anidado) = {CustomerId}

Este es el caso en el que GeneXus determina que las tablas base de cada For each son distintas y hay una especie de relación 1-N (pudiendo ser ésta indirecta, como veremos luego) entre las tablas que se recorren.

Es decir, por cada registro de la tabla base del For each principal, GeneXus encuentra que hay N relacionados con él, directa o indirectamente, en la tabla base del For each anidado.

Al encontrar esta relación, aplicará condiciones de filtro automáticas en el For each anidado, de forma tal de solo quedarse con esos registros relacionados.

El ejemplo del procedimiento en el que se imprimen todas las facturas del sistema, con sus detalles, cae dentro de esta categoría. En ese caso hay una relación 1-N directa entre las tablas que se recorren: para cada cabezal de factura, se lista el mismo, junto con todas sus líneas de factura, es decir, todos los registros de INVOICEDETAIL que están relacionados con el registro de INVOICE en el que se está posicionado en cada iteración.

Este es uno de los casos más comunes de For eachs anidados, donde se quiere recorrer una tabla, y para cada registro de la misma, recorrer otra tabla, relacionada con la primera por una relación N-1. GeneXus encuentra esta relación, y en la navegación interna solo recupera los registros asociados, y de ahí el nombre de “join” para este caso.

En el ejemplo presentado arriba ocurre lo mismo. La tabla base del primer For each es CUSTOMER, y la del segundo, INVOICE. Como encuentra atributo en común entre la tabla extendida del Foreach principal y la tabla base del anidado1, CustomerId, determina que ese atributo actuará como condición de filtro en la recorrida de la tabla del For each anidado.

---------------------------------------------------------------------------------------------------------------------------------------------------1 Esta es una forma de expresar formalmente lo que habíamos dicho en términos informales: relación directa o indirecta 1-N entre las tablas base. La relación será directa cuando la tabla base del principal tenga relación 1-N con la tabla base del anidado, es decir, sea superordinada de esta última. La relación será indirecta cuando esto no exista una relación directa entre las tablas base, pero sí entre la tabla extendida del primero y la tabla base del segundo. También será indirecta cuando la tabla extendida del anidado incluya a la tabla base del principal. De esto veremos ejemplos luego.

Page 201: Aplicaciones Genexus

193

Caso 1: Join

Veamos, por ahora intuitivamente, cómo hace GeneXus para determinar las tablas base. Los atributos utilizados en el For each externo son CustomerId y CustomerName, por lo que la tabla base de este For each será claramente CUSTOMER. Observemos que solo participan en la determinación de esta tabla base los atributos del For each principal, no los del anidado.

Luego GeneXus debe encontrar la tabla base del For each anidado. Los atributos que participan son InvoiceId, InvoiceDate y InvoiceAmount, es decir, los atributos internos a este For each. Observemos que estos atributos no pertenecen a la tabla extendida del principal, que era CUSTOMER. Por tanto se pasa a determinar su tabla base como la de cualquier For each simple: la tabla extendida de INVOICE contiene a todos los atributos del For each anidado, y es la mínima tabla extendida que los contiene. Por lo tanto, INVOICE será elegida como tabla base del segundo For each.

Observemos, nuevamente, que no explicitamos cláusula where en el For each anidado para filtrar las facturas del cliente del For each principal. Justamente, por tratarse de tablas relacionadas por una relación 1-N directa, esta condición es aplicada implícitamente por GeneXus y puede verse claramente en el listado de navegación que se muestra arriba.

Hay otro hecho interesante que podemos observar en este listado: si bien en el For each anidado no especificamos cláusula order, GeneXus no eligió el orden por clave primaria de la tabla base sino por el atributo relación, CustomerId. De esta manera, está optimizando automáticamente la consulta.

Acá se presenta, pues, una excepción a la regla que enunciaba que cuando no se especifica cláusula order en un For each, GeneXus determina como orden el de la clave primaria de la tabla base de dicho For each.

Page 202: Aplicaciones Genexus

194

Caso 1: Join• Ejemplo: Listado de todas las facturas por país

For eachprint countryFor each

print invoiceEndfor

Endfor

{CountryId, CountryName}

{InvoiceId, InvoiceDate, InvoiceAmount}

COUNTRY ⊂ ext(INVOICE) por lo que hay una relación 1-N indirecta condición implícita: se listan las facturas del país.

base(principal) ⊂ ext(anidado)

INVOICE

CUSTOMER

CustomerId

COUNTRY

CountryId

Si queremos realizar un listado de las facturas emitidas por país, tenemos otro caso de For eachsanidados con distintas tablas base, donde la información que se quiere listar está relacionada.

Aquí queremos recorrer las tablas COUNTRY e INVOICE.

Observemos que si bien no están relacionadas directamente, sí lo están en forma indirecta. De hecho, COUNTRY pertenece a la tabla extendida de INVOICE. Por lo tanto, por cada factura se puede encontrar un solo país relacionado con la misma.

Hilando fino, este es un caso un poco más complejo que el anterior, porque si bien la tabla extendida del For each principal no tiene intersección con la tabla base del anidado (ext(COUNTRY) ∩INVOICE = φ), sin embargo sí existe una relación 1-N indirecta, y GeneXus la encuentra.

En este caso, la tabla base del For each principal está incluida en la extendida del anidado(COUNTRY ⊂ ext(INVOICE)), por lo que hay una relación 1-N indirecta.

Por este motivo, no necesitamos especificar cláusula where en el For each interno para filtrar las facturas del país del For each principal.

Esto puede verse claramente en el listado de navegación, que mostrará el filtro:“CountryId = CountryId” para el segundo For each, pero esta vez como ‘Constraint’ dado que no puede optimizar la recorrida.

Puede probar el lector este caso en GeneXus y estudiar detenidamente el listado de navegación resultante.

Page 203: Aplicaciones Genexus

195

Caso 2: Producto Cartesiano

• Distintas tablas base, pero no existe relación 1‐N directa ni indirecta entre las mismas. 

• El resultado que obtenemos es el producto cartesiano de dichas tablas: para cada registro de la tabla base del For each principal, se recuperan todos los registros de la tabla base del anidado.

ext(principal) ∩ base(anidado) = φy

base(principal) ⊄ ext(anidado)

En este caso GeneXus no logra encontrar una relación 1-N directa o indirecta entre las tablas y por lo tanto no aplica filtros implícitos a los registros del For each anidado, vale decir, realiza un producto cartesiano entre las tablas.

El caso se da cuando:• ext(For each principal) ∩ base(For each anidado) = φ y• base(For each principal) ⊄ ext(For each anidado)

Para cada registro de la tabla base del For each principal se recorre toda la tabla base del For eachanidado.

Por ejemplo, si la tabla base de un For each fuera COUNTRY y la del anidado PRODUCT, evidentemente no existirá relación y se hará un producto cartesiano y se recorrerá para cada país, todos los productos.

Por supuesto que el programador podrá establecer filtros sobre los datos a recuperar, pero éstos ya no serán condiciones implícitas inferidas por GeneXus, sino especificadas explícitamente por el programador.

Page 204: Aplicaciones Genexus

196

Caso 3: Corte de Control

• Ejemplo: Para cada cliente que tiene facturas, listar sus facturas.

En el ejemplo que habíamos visto antes, del listado de clientes y sus facturas, ¿qué ocurre si un cliente no tiene facturas?

Como la tabla base del For each principal es CUSTOMER, el cliente sale impreso antes de saberse si tiene o no facturas.

Si no deseamos que esto ocurra, es decir, que salgan listados clientes que no tengan facturas, entonces la solución es acceder únicamente a las facturas, pues si un cliente está en esta tabla, ¡es porque está en una factura!.

Pero para poder agrupar las facturas por cliente, de forma tal de poder desplegarlas de ese modo, debemos recorrer la tabla INVOICE ordenada por CustomerId. De esta forma procesaremos la información de un cliente, y luego pasaremos al siguiente, para procesar su información, y asísucesivamente.

Si imaginamos un puntero que se va desplazando secuencialmente por la tabla INVOICE, podemos escribir el pseudocódigo de nuestro procedimiento como sigue:

1. Para el registro apuntado, retener el valor del atributo de corte o agrupamiento, CustomerId.

2. Acceder a la tabla CUSTOMER (que está en la extendida de INVOICE) para recuperar el CustomerName e imprimirlo junto con el CustomerId (“print customer”)

3. Mientras el valor de CustomerId del registro apuntado coincida con el valor retenido en el paso 1 (aquí se procesan todas las facturas del cliente)

a. Imprimir InvoiceId, InvoiceDate e InvoiceAmount del registro apuntado.(“print invoice”)

b. Avanzar el puntero al siguiente registro y volver al paso 3.

4. Volver al paso 1. (cuando se llegó a este punto, es o bien porque se llegó al fin de tabla o bien se cambió de cliente).

Page 205: Aplicaciones Genexus

197

Caso 3: Corte de Control• Ejemplo: Para cada cliente que tiene facturas, listar sus facturas.

For each order CustomerIddefined by InvoiceDate

print customerFor each

print invoicesEndfor

Endfor

orden determina el criterio de corte

Cada vez que cambia el cliente se define un nuevo grupo

Se utilizó “defined by” para que la tabla base fuera INVOICE y no CUSTOMER y así implementar corte de control y no join.

Source

Layout

GeneXus brinda una forma de implementar lo anterior de una forma absolutamente sencilla.

El pseudocódigo visto en la página anterior se implementa en GeneXus con el par de For eachsanidados que se muestran arriba.

Si se compara este código con el que vimos unas páginas atrás para el caso de join, vemos que existen solamente dos diferencias: la cláusula order que aparece en este código, en conjunción con el defined by. Con solo esos dos cambios al listado original, cambiamos radicalmente el comportamiento, puesto que en este caso solamente se listarán los clientes si tienen facturas.

En este caso, ambas cláusulas (order y defined by) son indispensables para que este procedimiento funcione del modo que queremos. Si agregamos solo una de ellas, pero no la otra, el resultado seráotro.

No en toda implementación de un corte de control deberá especificarse una cláusula defined by en el For each principal, mas sí una cláusula order.

La cláusula order es indispensable, porque es la que especifica por qué atributo o conjunto de atributos se realizará el corte (o agrupamiento). Es decir, especifica esa información común al grupo, que se procesará una sola vez (dentro el código del For each externo).

La cláusula defined by no es indispensable en todos lo casos. En este sí lo fue, porque de no especificarla, GeneXus determinaría como tabla base del For each principal CUSTOMER, que no es lo que queremos (pues no queremos implementar un join, cosa que ya hicimos antes, sino un corte de control, para solo recorrer la tabla INVOICE).

Pero también podríamos haber utilizado otra solución para modificar la tabla base del For eachprincipal: utilizar en vez del defined by el comando print if detail dentro del cuerpo del primer For each(este comando le dice a GeneXus que tome como tabla base del For each, la que determine para el anidado).

Page 206: Aplicaciones Genexus

198

Caso 3: Corte de Control

Condiciones que deben cumplirse para implementar Cortes de Control: 

1. For each anidados

2. Tienen la misma tabla base 

3. ¿Cuántos For each? Uno más que la cantidad de cortes

4. Debemos establecer en la cláusula order de cada For eachexterno, el atributo o conjunto de atributos por los que queremos “cortar”. 

Un corte de control es bien simple de implementar y puede hacerse siguiendo las consideraciones anteriores. En el order del For each más externo, debemos mencionar el “primer” atributo de corte, en el orderdel segundo For each debemos mencionar el “segundo” atributo de corte, y así sucesivamente. No es obligación mencionar atributo/s en el order del For each más interno (en todos los demás For each sílo es).

Corresponde al caso en el que nos interesa trabajar con la información de una tabla, pero agrupada por algún atributo o conjunto de atributos.

Los cortes de control pueden ser simples, dobles, triples, etc.

A continuación veremos un ejemplo de un corte de control doble.

Page 207: Aplicaciones Genexus

199

Ejemplo: Corte de control doble

Supongamos que queremos como antes listar los clientes y sus facturas, pero queremos agrupar las facturas de cada cliente por fecha. Es decir, queremos mostrar, para cada cliente, para cada fecha, las facturas existentes.

Ejemplo:

Customer: 1 Juan Pérez

Date: 12/05/05Invoice Total

1 15

Date: 01/01/06Invoice Total

9 353 30

Customer: 3 María Donoso

Date: 06/06/05Invoice Total

2 20Date: 12/08/05

Invoice Total4 408 15

Date: 02/02/06Invoice Total

7 20

Como ahora queremos agrupar por cliente, y dentro de ese grupo por fecha de factura, necesitamos tres For eachs anidados:

For each order CustomerIddefined by InvoiceDate

print customerFor each order InvoiceDate

print dateFor each

print invoiceEndfor

EndforEndfor

Como ejercicio, sigamos todos los pasos que realiza GeneXus para inferir el comportamiento del procedimiento.

1. Determinación de la tabla base de cada For each

Como siempre, para determinar las tablas base de For eachs anidados, se empieza de afuera hacia adentro, determinando la de cada For each, sin tomar en cuenta los atributos de los For eachs internos al que se está considerando.

Page 208: Aplicaciones Genexus

200

2. Determinación de la navegación

Luego de determinadas las tablas base, GeneXus determina la navegación. Como en este caso son tres For eachssobre la misma tabla base, se trata de un doble corte de control.

Podemos pensar que cuando hablamos de corte de control, ya sea simple, doble, triple, cuádruple, etc., tenemos un solo puntero, que se utiliza para avanzar en los registros de la tabla base.

Recordemos que la cláusula order es fundamental para establecer el criterio de corte en cada par de For eachs.

Como en nuestro caso queremos agrupar por CustomerId y luego, para todas las facturas con ese cliente, agrupar por InvoiceDate, entonces tendremos que ordenar el primer For each por CustomerId y el inmediatamente anidado por InvoiceDate.

En el ejemplo estamos diciendo que:

Mientras no se alcance el fin de tablaImprimir los datos del cliente de la factura actualMientras no cambie el cliente

Imprimir la fecha de la factura actualMientras no cambie la fecha

Imprimir los datos de la factura actual (nro y total)Avanzar el puntero al siguiente registro

For each order CustomerIddefined by InvoiceDate

print customerFor each order InvoiceDate

print dateFor each

print invoiceEndfor

EndforEndfor

Tabla base 2do. For eachIntervienen los atributos de los lugares señalados en negrita y como todos ellos están incluidos en la extendida del 1er. For each, entonces se determina la misma tabla base: INVOICE

For each order CustomerIddefined by InvoiceDate

print customerFor each order InvoiceDate

print dateFor each

print invoiceEndfor

EndforEndfor

Tabla base 3er. For eachIntervienen los atributos de los lugares señalados en negrita y como todos ellos están incluidos en la extendida del 2do. For each, entonces se determina la misma tabla base: INVOICE

For each order CustomerIddefined by InvoiceDate

print customerFor each order InvoiceDate

print dateFor each

print invoiceEndfor

EndforEndfor

Tabla base 1er. For eachSolo intervienen los atributos de los lugares señalados en negrita.

Mínima tabla extendida que los contiene: ext(INVOICE)

Page 209: Aplicaciones Genexus

201

Recomendamos al lector implementar en GeneXus este procedimiento y observar detenidamente el listado de navegación.

Verá que GeneXus elige un único orden, para el que no tiene un índice creado: el compuesto por la concatenación de los órdenes de cada For each con cláusula order. Esto resulta evidente si pensamos en términos de un único puntero que se va desplazando por la tabla base.

Una vez determindo el Order del Corte de Control se optimizará, buscando el mejor índice teniendoen cuenta las condiciones explícitas o implícitas del nivel.

Resumen: Determinación general de las tablas base

Se procede en forma ordenada, determinando cada vez la tabla base de un nivel de anidación, yendo de afuera hacia adentro: primero se determina la tabla base del For each más externo, luego del que está anidado a éste y así sucesivamente.

Determinación tabla base del For each externoSe determina a partir de los atributos que aparecen dentro de ese For each: cláusulas order, where, defined by y cuerpo del For each, exceptuando los atributos que estén dentro del For eachanidado. No participan los atributos que estén dentro del When none, en caso de que el For eachprincipal tenga esta cláusula. Al igual que en el caso de un For each simple, se encuentra la mínima tabla extendida que contenga los atributos mencionados.

Determinación tabla base del For each anidadoPodemos vernos tentados a pensar que por analogía lo que se debería hacer es extraer los atributos del For each anidado, y hacer lo mismo que antes, es decir, encontrar la mínima tabla extendida que contenga a esos atributos, como si se tratase de un For each independiente. ¡Pero no son For eachsindependientes!

Para el For each anidado, GeneXus se fija primeramente si los atributos utilizados dentro del cuerpo del mismo están incluidos o no dentro de la tabla extendida previamente determinada. En caso afirmativo, GeneXus determina que la tabla base del For each anidado será la misma que la del Foreach principal (y será un caso de corte de control).

En caso contrario, se determina de la siguiente manera: busca la mínima tabla extendida que contenga a todos los atributos del For each anidado, tratando de encontrar aquella que tenga alguna relación con la tabla base del for each principal.Si no encuentra una tabla extendida que contenga a todos los atributos del For each anidado y que además esté relacionada, se queda con la tabla extendida mínima que contenga a los atributos aunque no tenga relación.

Page 210: Aplicaciones Genexus

202

Comandos de control

if condbloque1

[elsebloque2]

endif

do while condbloque

enddo

do casecase cond1

bloque1[case cond2

bloque2]......

[case condnbloquen]

otherwisebloquen+1

endcase

for &var=inicio to fin [step salto]bloque

Endfor

for &var in Expressionbloque

Endfor

Los comandos introducidos son similares a los existentes en los lenguajes de programación imperativa conocidos, por lo que no incluimos documentación de este tema. Puede encontrarla en el curso no presencial o en el Help de GeneXus. Los dos últimos, no obstante, incorporan algunos elementos interesantes sobre el manejo de arrays y de colecciones1 en GeneXus, por lo que mostraremos algunos ejemplos.

For to step: • inicio, fin son expresiones numéricas• salto es una constante numérica• var es alguna variable numérica• bloque es una sucesión de comandos válidos del lenguaje

Permite iterar una cierta cantidad de veces: desde el valor inicio que toma la variable &var cuando se ingresa al bucle, hasta el valor fin que tomará la misma luego de cierta cantidad de iteraciones. De iteración en iteración la variable &var se va incrementando automáticamente en una cantidad igual a salto. El valor por defecto de salto es 1, por lo que si no se especifica la cláusula step el incremento de la variable será de uno en uno. El valor de salto puede ser negativo y en ese caso se irádecrementando la variable de iteración en iteración.

EjemploFor &i = 1 to 5

&ok = PInvoicing.udp( &month )Endfor

--------------------------------------------------------------------------------------------------------------------------------1 Las colecciones representan listas de largo variable. Se verán cuando estudiemos el tipo de datos estructurado (SDT).

Page 211: Aplicaciones Genexus

203

For in Expression:• Expression es cualquier expresión cuyo valor sea una colección, vector o matriz. • var es una variable que debe tener el mismo tipo de datos que los elementos de Expression.

Esta estructura de programación permite recorrer con menos código una colección o una variable array de una o más dimensiones. Se almacena en la variable &var los valores de cada elemento de la colección, array o matriz.

Para el caso de arrays de una dimensión:

for &var in &varArray()… // code

Endfor

el código se expande (es equivalente) a:&x = 1

do while &x <= rows(&array())&var = &Array(&x)bloque&x += 1

enddo

En el caso de dos dimensiones:

for &var in &varMatrix()… // code

Endfor

el comando se expande (es equivalente) a: &x = 1 do while &x <= rows( &array() )

&y = 1do while &y <= cols( &array() )

&var = &array( &x, &y )bloque&y += 1

enddo&x += 1

enddo

También puede ser una variable colección de cualquier tipo, incluyendo una variable con la propiedad Collection en 'False' pero de un tipo de datos 'SDT collection' .

for &var in &collection...endfor

La expresión también puede no ser una variable, por ejemplo en el caso del resultado de un DataProvider o de un Procedure:

for &var in DataProvider(parms)...Endfor

for &var in Procedure(parms)...endfor

Consideraciones:

• No es posible modificar los valores de la colección, array o matriz en la recorrida. Esto significa que cambios en el valor de &var en el alcance de la estructura, no afectan al correspondiente valor de la &collection o del &array(&x), o de &array(&x, &y)).

• No es posible obtener la posición de la colección/array/matriz durante la recorrida, para esto es necesario definir una variable que actúe como contador.

•Estas estructuras pueden anidarse para recorrer varios arrays, matrices o colecciones. Esto incluye el caso de que se invoque a una Subrutina que también tiene un For In Expression.

•Al igual que en un For Each o un Do While, es posible incluir comando que “corten” la recorrida, como Exit o Return.

Page 212: Aplicaciones Genexus

204

• Print• Se utiliza para imprimir en la salida un Printblock definido en el Layout• Sintaxis: Print nombrePrintBlock

• Header• Se utiliza para definir lo que se quiere imprimir como encabezado de cada página 

del listado • Sintaxis: Header

bloqueend

• Footer• Define las líneas de pie de página a ser impresas al final de cada página del 

procedimiento.• Sintaxis: Footer

bloque

end

Comandos de impresión

Aquí veremos algunos comandos de impresión, que permiten diseñar la salida del procedimiento.

Print

donde nombrePrintBlock es el identificador de un Printblock del Layout. Si no existe en el Layout un Printblock con ese nombre, al intentar salvar el objeto se desplegará un mensaje de error informando sobre esta situación.

De esta forma se implementa la impresión en la salida de los Printblocks del Layout.

Cuando el Printblock que se quiere imprimir no contiene atributos, entonces este comando se puede utilizar en cualquier lugar del Source.

Los atributos indican acceso a la base de datos y este acceso no puede realizarse en cualquier lado, sino únicamente dentro del comando específico para ello, esto es, el comando For each.

Por tanto no es correcto escribir el comando print fuera de un “For each” si el Printblock que se estáqueriendo imprimir contiene atributos.

La única excepción a esta regla se produce cuando los atributos del Printblock están incluidos entre los parámetros recibidos por el procedimiento, pues en este caso no es necesario acceder a la base de datos para recuperar sus valores, dado que ya vienen instanciados.

Header

Aquí se define lo que se quiere imprimir como encabezado de cada página del listado. Este encabezado es opcional. Si no se especifica, entonces las páginas del listado no tendrán encabezado.

Page 213: Aplicaciones Genexus

205

Ejemplo: En el procedimiento en el que queríamos imprimir un listado con el código, nombre y país de cada uno de los clientes de nuestro sistema, si queremos que en cada página del listado aparezca el encabezado: “CUSTOMERS REPORT”, entonces alcanza con escribir en el Source:

HeaderPrint title

End

Donde “title” es el nombre de un Printblock del Layout que contiene este texto.

También podríamos haber escrito directamente: Print title al comienzo del Source, pero en este caso, si el listado tiene varias páginas, solo saldrá impreso este texto en la primera. En el otro caso, saldráen cada una de las páginas, como encabezado.

FooterDefine las líneas de pie de página a ser impresas al final de cada página del procedimiento.

Los comandos del bloque de código son ejecutados cuando se llega al final de una página.

Ejemplo: Footer

print endOfPageTextend

donde endOfPageText es el nombre de un Printblock del Layout

Page 214: Aplicaciones Genexus

206

Diseño de la salida

Existen algunos comandos para diseñar la salida del procedimiento. Presentamos aquí algunos a los efectos de la documentación.

MT nlines: nlines es el número de línea en el que se quiere empezar a imprimir el listado. En caso de no especificarse un valor se asume el valor por defecto que es 0.

MB nlines: nlínes es el número de líneas que se desea dejar como margen inferior.En caso de no especificarse un valor se asume el valor por defecto que es 6.

PL nlines: Setea el largo de página. El número de líneas que será impreso es el número especificado menos el margen de abajo (valor por defecto es 6). Ej: PL 66Setea el largo de página a 66 líneas, aunque sólo 60 líneas serán impresas en el form, con un margen inferior de 6 líneas.

CP nlines: Si queda en la página actual un número de líneas mayor o igual al número especificado, continúa imprimiendo en la misma página. De lo contrario, pasa a imprimir en la próxima página (fuerza a un salto de página).

Lineno nline: Define el número de línea donde va a ser impresa la siguiente línea. Si el número de línea actual es mayor al número especificado, entonces, la línea será impresa en la próxima página. El conteo de líneas comienza en la línea 0.

Eject: Fuerza a un salto de página.

Noskip: Tiene que estar inmediatamente después de un Printblock. Si el comando se encuentra entre dos líneas, este comando las imprimirá en la misma línea.

Page 215: Aplicaciones Genexus

207

Procedimientos PDF

• Configurar las propiedades:• Main Program = True

• Call Protocol = HTTP

• Report Output = ‘Only to file’

• Regla• Output_file( ‘xx.pdf’, ‘PDF’)

En Web los listados solamente pueden ser PDF y se deben configurar las propiedades y regla anteriores para que funcionen.

Definición de un objeto como main

Al definir que un objeto es main (en este caso un procedimiento, pero podría ser una transacción, web panel, etc.), GeneXus genera un programa ejecutable con la lógica del objeto mismo y la de todos los objetos invocados directa o indirectamente por él.

El programa ejecutable generado se podrá compilar y ejecutar de forma independiente, es decir, al seleccionar Build / Run se verá como programa independiente del Developer Menu y podrácompilarse y ejecutarse.

La definición de un objeto como main se realiza editando las propiedades del objeto, y configurando la propiedad Main program del mismo con valor True.

Page 216: Aplicaciones Genexus

208

Condiciones

• Permiten especificar condiciones globales que deberán cumplir los datos a ser recuperados.

• Ejemplo:

En esta sección se permiten establecer condiciones que deben cumplir los datos para ser recuperados.

Una “condición” es equivalente a la cláusula “where” del comando For each (incluso tiene la misma sintaxis) con una salvedad: mientras que la cláusula “where” está ligada a un For each específico: aquel al que pertenece, las “condiciones” están ligadas a todos los For eachs del Source en los que tenga sentido aplicarlas.

¿Y para qué For eachs tiene sentido aplicarlas?Las condiciones generalmente involucran atributos. Si en la tabla extendida de un For each se encuentran los atributos que intervienen en una “condición”, entonces la misma se aplicará a este Foreach para filtrar los datos quedándose únicamente con aquellos que satisfagan tal condición.

En el listado de navegación del procedimiento se indican los For eachs a los que se aplica cada condición de las especificadas en la sección “Conditions”.

Si en el Source del procedimiento “PrintCustomers” tenemos:

For eachPrint customer

Endfor

Entonces al especificar las condiciones que se muestran en la transparencia, estaremos filtrando los clientes, de acuerdo a las condiciones (es equivalente a tener las condiciones como “where”).

Page 217: Aplicaciones Genexus

209

Condiciones• Si el Source del procedimiento es:

For eachPrint customer

Endfor

For eachPrint invoice

Endfor

For eachPrint product

Endfor

For eachwhere CustomerName>=&start

Print customerEndforFor eachwhere CustomerName>=&startwhere InvoiceId < 100

Print invoiceEndforFor each

Print productEndfor

Conditions: CustomerName >= &Start;InvoiceId < 100;

donde:• “customer” es un Printblock que contiene los atributos CustomerId, CustomerName, CountryName• “invoice” es un Printblock que contiene los atributos InvoiceId, CustomerId, CustomerName, InvoiceDate, InvoiceAmount• “product” es un Printblock que contiene los atributos ProductId, ProductDescription, ProductStock

Si el procedimiento anterior tiene definidas las condiciones mostradas arriba, el procedimiento seráequivalente a uno sin “condiciones” y con el Source que se muestra a la derecha.

Observemos que en este caso las condiciones se traducen en cláusulas where pero que se aplican solo a los For eachs para los que tiene sentido aplicarlas. En la tabla extendida del último For each no se trabaja con nombre de cliente, ni con identificador de factura. No tiene sentido aplicar las condiciones en este For each ya que no existe ninguna relación. En el primero, solo tiene sentido aplicar la que involucra a CustomerName y no la otra.

ObservaciónLos atributos involucrados en las “condiciones” no participarán en la determinación de las tablas base de los For eachs del Source (a diferencia de los filtros que se especifican mediante cláusulas where).

Es decir, las tablas base de los For eachs que aparezcan en el Source se determinan sin mirar las “condiciones”. Una vez determinadas, recién en ese momento las condiciones son examinadas para determinar a cuáles For eachs se aplicarán y a cuáles no.

Lo mismo ocurre con los atributos que se reciban como parámetro. Aplicarán como filtro global por igualdad para los For eachs en los que tenga sentido, pero no participarán en la determinación de las tablas base.

Page 218: Aplicaciones Genexus

210

• Formas de filtrar los datos:

• Cláusulas Where

• Condiciones

• Regla Parm (Atributos recibidos como parámetros)

Ejemplo: Parm(Att1 ... Attn)  

Filtros en la navegación

Participan en determinación de tabla base

NO participan en determinación de tabla base

Resumimos aquí las distintas formas de filtrar en un procedimiento la información a recuperar de la base de datos:

a. cláusulas whereb. Condicionesc. parm( att, ..., att )

Estudiemos las diferencias y similitudes entre ellas.

1. Las cláusulas where aplican exclusivamente al For each en el que se encuentran, mientras que los filtros especificados como condiciones o los que quedan determinados por los atributos en la regla parm son globales, es decir, aplicarán a todos los For eachs del Source en los que tenga sentido aplicarlos.

2. Los filtros que quedan determinados al recibir atributos en la regla parm son filtros por igualdad, es decir, para los For eachs en los que tenga sentido aplicarlos, se instanciarán únicamente los registros que tengan el mismo valor que el recibido por parámetro. En cambio, los filtros especificados en las cláusulas where de un For each o en las condiciones pueden ser expresiones booleanas cualesquiera, incluso compuestas.

3. Mientras que los atributos que aparecen en las cláusulas where participan en la determinación de la tabla base del For each donde se encuentran, los que aparecen en las condiciones o en la regla parm no lo hacen. Recién entran en juego LUEGO de determinadas las tablas base de los For eachs del Source.

Page 219: Aplicaciones Genexus
Page 220: Aplicaciones Genexus

211

Objeto Data Selector

DS

Page 221: Aplicaciones Genexus

212

Data Selectors - Concepto

• Objeto GeneXus: permite almacenar un conjunto de orders, filtros y un defined by, con el objetivo de reutilizar navegaciones (será “referenciado”desde distintas consultas y cálculos).

CREAMOS DATA SELECTOR CON DICHO FILTRO (+ ORDER + DEFINED BY)…Y LO REFERENCIAMOS DESDE LOS LUGARES NECESARIOS

En varios objetos, se repite la necesidad de consultar los clientes activos ( CustomerStatus= Status.Active )

Por ejemplo:

• Procedimiento que imprime clientes activos, agrupados por sexo.• Procedimiento que aplica un descuento, sólo para clientes activos.• Web Panel que muestra el total de ventas por cliente, sólo de clientes activos.

Ejemplo:

Customer{

CustomerId*CustomerNameCustomerAddressCustomerGenderCustomerStatus

}

El atributo CustomerStatus está basado en un dominio enumerado, Status, que tiene 3 valores:•Active•On Hold•Closed

Los clientes activos serán aquellos que tengan el valor Status.Active.

Page 222: Aplicaciones Genexus

213

Data Selectors - Definición

• Crear objeto de tipo “Data Selector”, darle un nombre y definirlo:

La estructura consta de:

• Parameters: Parámetros recibidos desde la “invocación” del Data Selector, para ser usados en conditions.• Conditions: Condiciones para filtrar los datos a ser recuperados.• Orders: Orders condicionales (cada order con sus atributos separados por coma y when opcional).• Defined by: Atributo o lista de atributos que colaboran en la definición de la tabla base final.

Page 223: Aplicaciones Genexus

214

Data Selectors - Ejemplo

CustomerStatus= Status.Active

Primer ejemplo planteado (Cont.): En varios objetos de una KB, se repite la necesidad de consultar a los clientes activos

Luego de definido un Data Selector, puede ser referenciado en:

• Comandos For Each• Grupos de Data Providers• Fórmulas Aggregate• Grids en Web Panels

Ejemplo:

Customer{

CustomerId*CustomerNameCustomerAddressCustomerGenderCustomerStatus

}

Definimos Data Selector: “ActiveCustomers”:

La forma de referenciar a un Data Selector dependerá desde cuál de los casos se desee invocar. Veremos la sintaxis para cada caso.

Page 224: Aplicaciones Genexus

215

Data Selectors - Beneficios

• Ahorro y reutilización de código: Se realiza cierta definición unavez y se reutiliza en varias consultas y cálculos en la KB.

• Facilitan el mantenimiento: Se cambia la definición en un únicolugar y el cambio aplica automáticamente a todo lugar de la KB en el que se utilice.

• Optimizan el conocimiento: Facilitan el entrenamiento de personal nuevo para un proyecto, gracias al encapsulamientoque proveen.

Page 225: Aplicaciones Genexus

216

Data Selectors – UsosEn For Each…

Con cláusula USING: interviene en la determinación de la tabla base.

Con operador IN: no interviene en la determinación de la tabla base.

Dos maneras de uso:

• Con cláusula USING• Con operador IN en cláusula WHERE

Importante:

• Un Data Selector siempre tiene tabla base.

• Según la forma de uso, los atributos presentes en la definición del Data Selector intervienen o no en la determinación de la tabla base del For Each:

Page 226: Aplicaciones Genexus

217

For Each con cláusula USING

Sintaxis:

Ejemplo 1:

Ejemplo 2:

Esto se Expande a:

For Each USING DataSelectorName([[parm1 [,parm2 [, ..] ])……

EndFor

For Each USING ActiveCustomers()……

EndFor

Data Selectors – UsosEn For Each…

For Each USING ActiveCustomers()Where CountryName = "Uruguay"

…EndFor

For EachWhere CustomerStatus = Status.ActiveWhere CountryName = "Uruguay"

…EndFor

Clientes activosde Uruguay

ATRIBUTOS DEL DATA SELECTOR PARTICIPANEN DETERMINACIÓN DE TABLA BASE DEL FOR EACH

Nota:

La performance será la misma si se escriben 2 where en el For Each que si se referencia un Data Selector en el For Each (que tiene definida una condition) + un where en el For Each.

GeneXus siempre tratará de optimizar el código generado, sin embargo no más por utilizar el concepto de Data Selectors , ya que su objetivo como venimos explicando, es: centralizar el conocimiento reusable en una sola definición y luego referenciar esa definición en todas las consultas y cálculos de la KB que aplique.

Dado que en estos ejemplos presentados, se está referenciando en For Each al Data Selector con cláusula USING, los atributos presentes en la definición del Data Selector intervienen en la determinación de la tablabase del For Each. Por esto, en ambos ejemplos, la tabla base del For each es: CUSTOMER.

Page 227: Aplicaciones Genexus

218

For Each con operador IN (en cláusulas WHERE)

Sintaxis:

Ejemplo:

Definición del Data Selector “InvoicesByDate”:

For EachWhere <attribute> IN DataSelectorName([[parm1 [,parm2 [, ..] ])

…EndFor

For EachWhere CustomerId IN InvoicesByDate(&FromDate, &ToDate)

…EndFor

Data Selectors – UsosEn For Each…

CONSISTE EN UNA CONSULTA APARTE / INDEPENDIENTE DEL FOR EACH

El atributo que antecede al operador IN debe pertenecer a la tabla extendida de la tabla base del Data Selector

TABLA BASE: INVOICE

• SE GENERA UN SELECT PARA EL DATA SELECTOR, INDEPENDIENTE DEL SELECT QUE SE GENERA PARA EL FOR EACH

•ATRIBUTOS DEL DATA SELECTOR NO PARTICIPAN EN DETERMINACIÓN DE TABLA BASE DEL FOR EACH

En este ejemplo:

• La tabla base del Data Selector es: INVOICE

• El atributo que antecede al operador IN pertenece a la tabla extendida de INVOICE (CustomerId)… y la consulta asociada al Data Selector devolverá una lista de valores correspondientes a dicho atributo (devuelve “una lista de clientes” que tienen facturas en el rango de fechas dado).

• El For Each tiene su tabla base determinada por los atributos incluidos en el For Each y sin tener en cuenta a la información almacenada en el Data Selector.

• El For Each navegará su tabla base y extendida, filtrando los registros que contengan a alguno de los clientes de la lista devuelta por el Data Selector.

Page 228: Aplicaciones Genexus

219

Find | Max | Min | Sum | Count | Average

Expresión a ser buscada, maximizada, minimizada, sumada o promediada

[<CondiciónBúsqueda>] ['USING' <DataSelector> '(' <Parámetro1> ',' <Parámetro2> ',' <Parámetro3>')']

Valor a devolver si no hay registros que cumplan con <CondiciónAgg>

Data Selectors – UsosEn Fórmulas Aggregate…

• Es posible utilizar Data Selectors en fórmulas Aggregate tanto globales como locales.

• Sintaxis:

• Ejemplo:

NombreFormulaAggregate '(' <Expresión> ',' [<CondiciónAgg>] ',' [<ValorDef>]')'

atributo fórmula cant. de clientesactivos del país

Consideraciones acerca de la sintaxis de las fórmulas Aggregate:

Como se detalló en la diapositiva, en la sintaxis de las fórmulas Aggregate la expresión corresponde a la expresión a ser buscada, maximizada, minimizada, sumada o promediada. Puede ser un atributo (almacenadoo fórmula) o bien una expresión que involucre atributos, constantes, variables.

Sin embargo hay que tener en cuenta que:• Variables solo pueden involucrarse en fórmulas locales. • Para Sum y Average, el resultado de Expresión debe ser un valor numérico.• Únicamente para el caso de Count, no vale una Expresión sino un atributo.

Page 229: Aplicaciones Genexus

220

Data Selectors – UsosConsideraciones

• En  los  parámetros  del  Data  Selector  pueden  incluirse  tanto variables como atributos. • Incluir atributos implica que se filtre por igualdad por ellos.

• Un  mismo  Data  Selector  definido,  tendrá cierto comportamiento u otro y participará o no en  la determinación de  la  tabla base de  la  consulta dependiendo de  cómo  se haya “invocado” en el contexto que sea usado.

Page 230: Aplicaciones Genexus
Page 231: Aplicaciones Genexus

221

Fórmulas locales

Page 232: Aplicaciones Genexus

222

Fórmulas LocalesGeneralidades

• Además de definir fórmulas asociadas a atributos (globales, a nivel de la KB) también es posible definir fórmulas en el propio código.

• Llamamos a este caso de uso de las fórmulas: fórmulas inline o fórmulas locales.

• Es posible definir fórmulas inline = locales  en source de procedimientos, subrutinas, eventos, etc.

• Comportamiento depende de si se definen:  

• Dentro de For Each• Fuera de For Each

Page 233: Aplicaciones Genexus

223

• Tabla base de la fórmula = Tabla base del For Each.

• Es posible incluir en la definición de la fórmula:• atributos de la tabla base de la fórmula + extendida

• atributos de la tabla navegada por la fórmula + extendida

• variables

• Ejemplo:

For Each order CountryId&NumberCustomers = Count( CustomerName )

EndForATRIBUTOS QUE PERTENECEN A LA DEF. DE LA FÓRMULA NO PARTICIPAN EN DETERMINACIÓN DE TABLA BASE DEL FOR EACH

TABLA BASE FOR EACH = COUNTRY

TABLA BASE FÓRMULA = COUNTRY

TABLA NAVEGADA FÓRMULA = CUSTOMER

ATRIBUTO EN COMÚN: CountryId

Fórmulas LocalesDentro de For Each

Otro ejemplo de codificación posible es el que sigue, en el cual la fórmula se define en el propio where del For Each, para filtrar por dicho cálculo:

For each order CountryIdwhere Count(CustomerName)>50

…Endfor

Page 234: Aplicaciones Genexus

224

• No se está posicionado en ninguna tabla al momento de disparar la fórmulano hay tabla asociada a la fórmula.

• Es posible incluir en la definición de la fórmula:• atributos de tabla a ser navegada + tabla extendida• variables

• En este caso de uso, no hay filtros implícitos:

• Consideración importante: El disparo de la fórmula se realiza al comenzar el grupo donde se encuentra. Por lo tanto:

&CustomerId = 1&total = Sum(InvoiceAmount, CustomerId = &CustomerId)

Solución:&CustomerId = 1 sub ‘CalcAmount’do ‘CalcAmount’ &total = Sum(InvoiceAmount, CustomerId = &CustomerId)

endsub

For eachdefined by CustomerName

&total=sum(InvoiceAmount) VERSUS &total=sum(InvoiceAmount)

Endfor SUMARIZA FACTURASFILTRANDO POR CLIENTE SUMARIZA TODAS LAS FACTURAS

&CustomerId no tiene valor

Fórmulas LocalesFuera de For Each

Consideración importante

Una fórmula se dispara cuando comienza el grupo que la contiene.

Esto significa que si se tiene definida una fórmula con sus parámetros en determinada línea de código, los valores de los parámetros van a ser aquellos que fueron leídos cuando el grupo fue ejecutado en la base de datos. Entonces, si el grupo fue ejecutado en la base de datos, y luego de eso ud. asignó valores diferentes a los parámetros que involucrará en la definición de la fórmula, los valores de los parámetros que se tendrán en cuenta no serán los que usted asignó; por el contrario serán los leídos cuando se ejecutó el grupo que contiene a la fórmula en la base de datos.

¿Y cuándo se ejecutan los grupos?

- Cuando comienza un programa.- Cuando comienza un For Each.- Luego de un Endfor. - Cuando comienza una subrutina o un evento.

En particular como en este caso estamos explicando fórmulas locales definidas fuera de comandos ForEach, los ítems que aplican son 1, 3 y 4.

Lo mismo ocurre con las variables. Los valores de las variables que son tenidos en cuenta al momento de disparar las fórmulas, son los valores que las variables tienen asignados cuando el grupo que contiene a la fórmula se ejecuta. De modo que si escribimos el siguiente código:

&CustomerId = 1&total = Sum(InvoiceTotal, CustomerId = &CustomerId)

Page 235: Aplicaciones Genexus

225

La variable &CustomerId no tendrá valor cuando la fórmula se dispare.

Esto puede resolverse como sigue:

&CustomerId = 1 sub ‘AmountCalc‘do ‘AmountCalc‘ &total = Sum( InvoiceAmount, CustomerId = &CustomerId )

endsub

ya que así logramos un nuevo comienzo de grupo (cuando la subrutina comienza), y en ese momento la variable ya está cargada con el valor deseado. De modo que con esta solución, cuando la fórmula se ejecute la variable &CustomerId valdrá 1.

Page 236: Aplicaciones Genexus
Page 237: Aplicaciones Genexus

226

Tipos de datos estructurados

SDT

Page 238: Aplicaciones Genexus

227

SDT: Introducción

• Lenguajes de programación manejan:• Tipos de datos simples (Numeric, Character, etc.) 

• Tipos de datos compuestos.

• Ejemplo de Tipos de datos compuestos (registros o tipos de datos estructurados)

Type Client = Record

Name: Character(30)

Country: Character(20)

City: Character(20)

Phones: Record

Home: Character(15)

CellPhone: Character(15)

end;

end;

Luego se definen variables con este tipo de datos y se trabaja con ellas...

Page 239: Aplicaciones Genexus

228

SDT en GeneXus

• Se crean como cualquier otro objeto GeneXus.

• Editor similar al de estructuras de transacciones.

• SDT se compone de: miembros, subestructuras y colecciones:

botónderecho

El editor de tipos de datos estructurados es similar al editor de transacciones.

Contiene:Propiedad Name, con el nombre que identifica al miembro, subestructura o colección.Propiedad Type, en la cual se debe seleccionar un tipo de dato simple, un dominio, o un tipo de datos estructurado que ya se haya definido en la KB (propiedad Type solo adquiere valor si se está definiendo un miembro y no una subestructura o colección).Propiedad Is Collection, para indicar si el miembro representa una lista (en seguida veremos un ejemplo).

Obsérvese que una subestructura es un miembro compuesto, en lugar de ser uno simple. Es decir, es, en particular, también él, un tipo de datos estructurado.

Haciendo botón derecho sobre un miembro de la estructura, se despliega la ventana que se ve a la izquierda, donde se puede insertar otro miembro, o una subestructura.

Tip: Si se desea crear un SDT con exactamente la misma estructura que la de una transacción, entonces en lugar de definir uno a uno todos los miembros, subestructuras y colecciones, alcanza con arrastrar (hacer Drag & Drop) el nombre de la transacción desde el Folder View hacia la estructura en edición del SDT. De la misma forma, si se desea que un miembro de la estructura corresponda a un atributo, puede seleccionarse y arrastrarse el atributo desde el Work With Attributes (ventana editable desde opción View del menú de GeneXus) o insertarse con el diálogo Insert/Attribute del menú de GeneXus.

Page 240: Aplicaciones Genexus

229

• Ejemplo conteniendo colección:

Un country tiene muchas ciudades...

SDT en GeneXus

Marcando el check box Is Collection se abrirá una rama de la estructura como puede verse, donde se le pedirán dos nombres: el de la colección en sí, y el de cada ítem de la misma.

Como se verá a continuación, cuando se define una colección, junto con el SDT se estará creando implícitamente otro, que corresponderá a los items de la colección.

Esto se debe a que de esta forma se podrá luego definir una variable del tipo de datos del ítem, para luego agregarla a la colección.

Page 241: Aplicaciones Genexus

230

SDT: Utilización

• Se utilizan a través de variables.

• Los atributos no pueden ser SDT.

Id 1

Name Uruguay

Cities •

CityName Montevideo

CityName Colonia

CityName Paysandú

&country

A la derecha puede verse el diálogo de propiedades de una variable &country que se está definiendo dentro de algún objeto.

El SDT Country definido en la KB tal como se aprecia en la página anterior, da lugar a la creación de dos tipos de datos estructurados: uno correspondiente al propio tipo de datos “country” y otro correspondiente a los ítems de la colección “country.City”. El por qué de este último caso se debe a que uno podría querer definir una variable solo de ese tipo de datos, para luego agregarla con el método Add que ya mencionaremos, a la colección.

Obsérvese que la variable &country se ha definido del tipo de datos “country” que aparece en la lista obtenida al hacer clic en el combo box de la propiedad “Data Type” del diálogo de definición de propiedades de la variable.

Page 242: Aplicaciones Genexus

231

SDT: Utilización

• Para datos no repetitivos, se accede a cada miembro mediante el nombre, como propiedad de la variable.

Name Julia James

Country Uruguay

City Montevideo

Phones Home 555‐155.55.44

CellPhone 092‐155.12.33

&client.Name = ‘Julia James’&client.Country = ‘Uruguay’&client.City = ‘Montevideo’&client.Phones.Home = ...&client.Phones.CellPhone = ...

Page 243: Aplicaciones Genexus

232

SDT: Utilización• Ejemplo: Transacción que registra los recibos efectuados a los clientes y 

SDT basado en la transacción:

For each where BillId = 7&bill.BillDate= BillDate&bill.CustomerId = CustomerId&bill.CustomerName = CustomerName&bill.BillInvoicePeriodStartDate = BillInvoicePeriodStartDate&bill.BillInvoicePeriodEndDate = BillInvoicePeriodEndDate&bill.BillAmount = BillAmount

endfor

drag&

drop

En un proc. se carga &bill con datos delrecibo 7 de la BD...

...podría devolverse:parm(..., out: &bill)

...de tabla BILL

Aquí se presenta un ejemplo con el que continuaremos trabajando en lo que sigue. Agregamos a nuestra realidad una transacción de recibos. Supongamos que una vez al mes, se lanza un proceso de generación de recibos, en el que, tras elegir un período de facturación (usualmente todo el mes anterior) para cada cliente se sumarizan todos los montos de las facturas que se le efectuaron en dicho período, y se le genera un recibo (autonumber). La generación del recibo será automática (la realizará nuestro sistema); ese es un tema que veremos en breve.

Por ahora, supongamos que necesitamos un procedimiento que devuelva los datos de un recibo determinado de los generados automáticamente como explicamos recientemente (por ejemplo, el de id. 7). Una opción es acceder mediante un for each a la tabla BILL creada a partir de la transacción de igual nombre, y junto con la regla parm:

parm( out: BillDate, out: CustomerId, out: CustomerName, out: BillInvoicePeriodStartDate, out: BillInvoicePeriodEndDate, out: BillAmount);

implementar lo pedido.

La otra opción, es devolver toda esa información en una sola variable ¡estructurada!

parm( out: &bill);

cargada como se muestra arriba. Para ello se define un SDT basado en la transacción Bill (los SDTs no pueden tener el mismo nombre que una transacción, razón por la cuál le llamamos BILL_SDT). Para no tener que ingresar uno a uno los miembros del SDT de igual nombre que los atributos de la transacción, alcanza con arrastrar la transacción Bill desde el Folder View, dentro de la estructura del SDT y automáticamente se inicializará como se muestra arriba.

Page 244: Aplicaciones Genexus

233

SDT: Utilización• ¿Y si queremos devolver una lista de recibos?

• Opción 1: no modificar el SDT y agregar variable &bills colección:

For each where... &bill.BillDate= BillDate&bill.CustomerId = CustomerId&bill.CustomerName = CustomerName&bill.BillInvoicePeriodStartDate = BillInvoicePeriodStartDate&bill.BillInvoicePeriodEndDate = BillInvoicePeriodEndDate&bill.BillAmount = BillAmount&bills.Add( &bill )&bill = new Bill_SDT()

endfor

Supongamos que queremos devolver una lista de recibos (por ejemplo, los que se hayan efectuado en un rango de fechas dado).

Page 245: Aplicaciones Genexus

234

SDT: Utilización

&bills

&bill new

add

&bills.Add( &bill )

&bill = new Bill_SDT()

&bill.BillDate= BillDate&bill.CustomerId = ...&bill.CustomerName = ...&bill.BillInvoicePeriodStartDate = ...&bill.BillInvoicePeriodEndDate = ...&bill.BillAmount = ...

¡Bajo nivel! ¿No existirá otra forma de más alto nivel?

Hay que pedir nuevo espacio de memoria para la variable &bill, para la siguiente iteración.

Como veremos en breve, existe un modo mucho más sencillo, de más alto nivel, DECLARATIVO, de obtener la colección de SDTs cargada, sin tener que preocuparnos de realizar operaciones de bajo nivel, como agregar una variable a la colección y pedir memoria...

Page 246: Aplicaciones Genexus

235

SDT: Utilización en Data Provider

Bills{

Bill where ...{

BillDate= BillDateCustomerId = CustomerIdCustomerName = CustomerNameBillInvoicePeriodStartDate = BillInvoicePeriodStartDateBillInvoicePeriodEndDate = BillInvoicePeriodEndDateBillAmount = BillAmount

}}

Data Provider: procedimiento especializado, devuelve info estructurada

...este modo declarativo, por tanto de alto nivel, de cargar una colección de SDTs se conoce con el nombre de Data Provider. Podemos pensarlo como un procedimiento especializado, que devolverásiempre información estructurada (ya sea simple como colección).

Aquí presentamos el ejemplo, que luego ampliaremos cuando entremos de lleno en este tema.

Page 247: Aplicaciones Genexus

236

SDT: Utilización• Opción 2: modificar el SDT para que sea colección y luego 

trabajar de la misma forma, definiendo las variables:

&bills

&bill

Page 248: Aplicaciones Genexus

237

SDT: Utilización

• Para datos repetitivos, se accede a cada item mediante comando:

For &var in expressioncode

endfor

&var: variable de tipo de datos Aexpression: expresión cuyo tipo de datos

es colección de A, o arrayde A

For &bill in &billsmsg( &bill.Id.ToString() )msg( ‘Name:’ + &bill.CustomerName )...

endfor

Ejemplo: A = SDT

Es posible incluir comandos de “corte” de la recorrida, al igual que en for each o do while, como exit o return.

La variable &var va tomando los valores de cada posición de la lista.

No es posible obtener la posición del ítem durante la recorrida, para esto es necesario definir un variable que actúe como contador.

Como puede fácilmente inferirse, este comando es válido para colecciones de cualquier tipo de datos, no solo SDTs.

Page 249: Aplicaciones Genexus

238

SDT: propiedades

&cVar.Count Retorna la cantidad de items de la colección.

&cVar.CurrentItem Cuando una variable SDT collection se despliega en un form (como grid) permite seleccionar el ítem que se ha seleccionado con el mouse como línea del grid.

Los nombres de los miembros de una variable SDT se muestran comopropiedades:

Además, para variables collection:

Las propiedades Count y CurrentItem solo están disponibles para variables SDT Collection.

Page 250: Aplicaciones Genexus

239

SDT: operadores y métodos

&cVar.Add( &item [, Position]) Agrega ítem a colección en la posición relativa especificada. Si se omite se agrega al final. Position comienza en 1.

&cVar.Clear() Elimina todos los ítems de la colección

&var.Clone() Crea una nueva área de memoria y copia los datos de la variable en esta: &var1 = &var2.Clone()

&var.FromXML( &xml ) Carga variable SDT a partir de string conteniendo una estructura xml.

&cVar.Item( Position ) Retorna referencia al elemento con posición relativa Positionen la collection.

&cVar.Remove( Position ) Elimina ítem que se encuentre en la posición especificada y corre un lugar todas las posiciones.

&cVar.Sort(memberName ) Ordena los elementos de la colección de acuerdo a miembro.

&var.ToXml() Retorna un string con el formato XML de los datos de la variable SDT (que puede ser collection): ml = &var.ToXml()

&var = new SDT() Retorna una nueva referencia o puntero al SDT especificado

Aquí se presentan la mayoría de los métodos con los que cuentan los tipos de datos estructurados.

Algunos aplican a variables SDT no colección, se representan con &var, otros a colecciones, se representan con &cVar.Para la lista completa, así como ejemplos, acceder al wiki o al help de la versión.

Page 251: Aplicaciones Genexus

240

SDT: Ejemplo

• Método ToXml:Name Julia James

Country Uruguay

City Montevideo

Phones Home 555‐155.55.44

CellPhone 092‐155.12.33

&xml = &client.ToXml()

<Client><Name> Julia James </Name><Country> Uruguay </Country><City> Montevideo </City><Phones>

<Home> 555-155.55.44 </Home><CellPhone> 092-155.12.33 </Home>

</Phones></Client>

Page 252: Aplicaciones Genexus

241

SDT collection en FORM

• Si se inserta en un form una variable SDT collection:

aparece ventana para seleccionar los miembros a insertar

que se presentarán como grid que serácargado automáticamente :

Puede seleccionarse del SDT los miembros que quieren cargarse como columnas del grid. Obsérvese que en nuestro caso hemos omitido los miembros CustomerId, BillInvoicePeriodStartDate y BillInvoicePeriodEndDate.

Page 253: Aplicaciones Genexus
Page 254: Aplicaciones Genexus

242

Objeto Data Provider

DP

Page 255: Aplicaciones Genexus

243

DP: Escenario• Intercambio de información jerárquica entre aplicaciones, o 

dentro de una misma aplicación.

DataInterchange

APPLICATION A APPLICATION B

Sistemade

Facturación

Sistemade

Deudores/Acreedores

envío de info de los recibos

BillId: 2516Customer: John DrottsDate: 12/12/2008Amount: 1000

BillId: 158Customer: Dane SmithDate: 12/12/2008Amount: 750...

Supongamos que desde nuestro Billing System, queremos enviar a un sistema de deudores y acreedores, un listado de los recibos correspondientes a cierto período de facturación (es decir, para un período determinado se desea sumarizar para cada cliente el importe total que se le ha facturado y generarle un recibo).

Se trata de información jerárquica (enviaremos info de recibos, cada uno de los cuáles tiene determinados datos).

El formato más usual de intercambio de información jerárquica suele ser Xml, aunque no sabemos quédeparará el futuro en ese aspecto (por ejemplo se está volviendo común el formato Json).

Page 256: Aplicaciones Genexus

244

Procedimientos “procedurales”• ¿Cómo obtenemos los recibos para un rango de fechas dado?

for each using ActiveCustomers()&bill.BillDate = &today&bill.CustomerName = CustomerName&bill.BillInvoicePeriodStartDate = &start&bill.BillInvoicePeriodEndDate = &end&bill.BillAmount = sum( InvoiceAmount, InvoiceDate>=&start and

InvoiceDate <= &end andInvoicePendingFlag )

&bills.Add( &bill )&bill = new Bill ()...

endfor

¿Utilizando un procedimiento que reciba el rango de fechas de facturación: &start y &endy devuelva una colección de recibos: Bill?

Teniendo el mismo SDT Bill que definimos cuando estudiamos los tipos de datos estructurados (allí le llamamos Bill_SDT, aquí le llamaremos Bill), estamos utilizando un procedimiento con los siguientes parámetros:

parm( in: &start, in: &end, out: &bills );

siendo &start y &end variables de tipo Date que reciben el rango de facturación, y &bills una variable collectiondel SDT Bill.

Obsérvese que estamos utilizando el Data Selector ActiveCustomers para filtrar por clientes activos y utilizando la fórmula inline sum, en la que únicamente sumamos los totales de aquellas facturas que pertenezcan al cliente de la actual iteración del For each y cuyas fechas se encuentren en el rango dado y tengan el valor Trueen el atributo Booleano InvoicePendingFlag.

Este atributo será cambiado a False una vez que la factura haya sido procesada dentro del proceso de generación de recibos que iniciamos aquí pero que completaremos más adelante, cuando estudiemos las formas de actualizar la información de la base de datos (aquí solamente estamos obteniendo la información de los recibos, pero aún no los registraremos en la base de datos... ).

Page 257: Aplicaciones Genexus

245

• Lenguaje de Input• Lenguaje de Transformación• Lenguaje de Output

Procedimientos “procedurales”

Transformation OUTPUTINPUT

Ejemplo:

¿?

embebido dentro del código

¿La intencióndel

procedimiento?

For each using ActiveCustomers()&bill.BillDate = &today&bill.CustomerName = CustomerName&bill.BillInvoicePeriodStartDate = &start&bill.BillInvoicePeriodEndDate = &end&bill.BillAmount = sum( InvoiceAmount, ...)&bills.Add( &bill )&bill = new Bill()

endfor

Todo procedimiento toma un Input, y mediante alguna transformación, obtiene un Output.

Para obtener el Input se tiene cierto lenguaje (en GeneXus si se trata de la base de datos, nombrando los atributos alcanza, como se puede ver en el ejemplo, a la derecha de las asignaciones; así como también se obtiene de los parámetros). Para realizar la Transformación se tiene otro lenguaje (el código que podemos ver en el ejemplo) y luego para expresar el Output otro más.

Como puede verse, en el caso de los procedimientos GeneXus, tanto el Input como el Output se encuentran embebidos dentro del propio código de Transformación. Puede decirse entonces que el foco está puesto en la transformación.

De esta forma la intención del procedimiento, su salida, queda oscurecida dentro de ese código, que mezcla: • elementos de salida, • con elementos de transformación (en nuestro caso, el comando for each, el método add y el operador new, que implementan el armado de la colección de recibos) • y con elementos de entrada.

Page 258: Aplicaciones Genexus

246

• Lenguaje de Input• Lenguaje de Transformación• Lenguaje de Output

Bills using ActiveCustomers(){

Bill{

BillDate = &todayCustomerName = CustomerNameBillInvoicePeriodStartDate = &startBillInvoicePeriodEndDate = &endBillAmount = sum( InvoiceAmount, ...)

}}

Procedimientos “declarativos”

OUTPUTINPUT

FORMAT

TXTHTMLXMLJSONSDT...

Data Provider

hierarchical structure

Transformation

Intención claraBillsBill

BillDate: 12/12/08CustomerName: John Drotts...BillAmount 1000

BillBillDate: 12/12/08 CustomerName: Dane Smith...BillAmount: 750

...

Con un Data Provider, el foco está ubicado en el lenguaje de salida: obsérvese que se indica en una estructura jerárquica de qué se compone ese Output.

Luego, para cada elemento de la estructura jerárquica, habrá que indicar en el Source del Data Provider, cómo se calcula.

Por tanto, alcanza con observar el lado izquierdo para deducir cuál será la estructura resultante.

Luego, alcanzará con indicar el formato deseado para esa estructura jerárquica resultante...

Page 259: Aplicaciones Genexus

247

Procedimientos “declarativos”

BillsBill

BillDate: 12/12/08 CustomerName: John Drotts...BillAmount: 1000

BillBillDate: 12/12/08CustomerName: Dane Smith...BillAmount: 750

...

OUTPUTINPUT

FORMAT

TXTHTMLXMLJSONSDT...

Data Provider

hierarchical structure

Transformation

<Bills><Bill>

<BillDate>12/12/08</BillDate><CustomerName>John Drotts</CustomerName>...<BillAmount>1000</BillAmount>

</Bill><Bill>

<BillDate>12/12/08</BillDate><CustomerName>Dane Smith</CustomerName>....<BillAmount>750</BillAmount>

</Bill>

...</Bills>

Bill

Bill

Bills

BillDate 12/12/08

CustomerName John Drotts

... ...

BillAmount 1000

BillDate 12/12/08

CustomerName Dane Smith

... ...

BillAmount 750

• Lenguaje de Input• Lenguaje de Transformación• Lenguaje de Output

Luego, una misma información estructurada, podrá representarse utilizando los diferentes formatos existentes.

Esa es la idea del Data Provider. Si en el futuro aparece un nuevo formato de representación de información estructurada, el Data Provider continuará invariable... GeneXus implementará el método de transformación a ese formato, y solo habrá que utilizarlo.

Page 260: Aplicaciones Genexus

248

DBDB

INPUT

¿Estructuras jerárquicasen GeneXus? SDTs

Data Providers

Bill

BillBillDate 12/12/08

CustomerName John Drotts

... ...

BillAmount 1000

BillDate 12/12/08

CustomerName Dane Smith

... ...

BillAmount 750

CustomerId CustomerName CustomerStatus

1542 John Drotts A

1543 Dane Smith A

... ... ...

OUTPUT

invoices...

Hasta aquí hicimos un análisis descriptivo. Surge inmediatamente la siguiente pregunta: ¿cómo se representan en GeneXus las estructuras jerárquicas de datos?

Por tanto, la salida de un Data Provider será un SDT (o una colección de SDTs).

Luego, con esa salida puede realizarse lo que se desee, en particular, convertirla a formato XML, con el método toXml de los SDTs.

Veamos cómo declaramos la salida... no será de la forma convencional (como parámetro de out de la regla parm)...

Page 261: Aplicaciones Genexus

249

Data Providers

Bill

BillBillDate 12/12/08

CustomerName John Drotts

... ...

BillAmount 1000

BillDate 12/12/08

CustomerName Dane Smith

... ...

BillAmount 750

OUTPUT

Aquí vemos para el ejemplo que venimos estudiando, que teniendo el SDT definido Bills, collection, que coincide con la estructura que se infiere del Source del Data Provider ‘GetBills’, habrá que declarar ese SDT en la propiedad Output del Data Provider.

Pero no es la única posibilidad... veremos otra en la página siguiente, donde cobrará sentido la propiedad Collection.

Page 262: Aplicaciones Genexus

250

Data Providers

Bill

BillBillDate 12/12/08

CustomerName John Drotts

... ...

BillAmount 1000

BillDate 12/12/08

CustomerName Dane Smith

... ...

BillAmount 750

OUTPUT

Otra posibilidad (mismo resultado):

Si en lugar de tener el SDT collection Bills, tuviéramos el que aparece arriba, Bill, entonces podríamos programar el Source del Data Provider como vemos y luego configurar la propiedad Collection en ‘True’, con lo cuál se abrirá una nueva propiedad, Collection Name, que permitirá dar nombre a la colección.

Este Data Provider es equivalente al anterior.

Obsérvese que en este caso no es necesario poner la raíz de la jerarquía, Bills, puesto que se infiere de la propiedad ‘Collection Name’. De todas formas, si bien no es requerido, podría programarse el Sourceexactamente igual al anterior, es decir, con el grupo Bills encabezando la jerarquía.

Bills{

Bill using ActiveCustomers(){

...}

}

Nota: la cláusula using, así como las where que veremos luego, order, etc., podrán especificarse tanto a nivel del grupo Bills, como del grupo Bill, en casos como este. Volveremos sobre este tema más adelante.

Page 263: Aplicaciones Genexus

251

Data Provider

• Objetivo: Retorno de datos estructurados.

• Con Procedimiento: hay que armar el  SDT  con operaciones de bajo nivel. 

• Con  Data  Provider:  facilidad  de  escritura y  claridad.  Es declarativo  independiente de implementación.

para devolver datos estructurados utilizaremos un DP en    

lugar de un Procedimiento.

Los Data Providers atacan eficientemente un tipo de problema: aquel que consiste en retornar datos estructurados. Para ese tipo de problemas contábamos con los procedimientos, pero su desventaja evidente era que necesitábamos implementar la forma de armar esas estructuras con operaciones de bajo nivel, como agregar un ítem a una colección con Add, y pedir memoria (new). Asimismo, si hubiera que hacer cálculos complejos para dar valor a cada miembro de la estructura, quedarían en el código embebidos los elementos de la salida, sin que fuera sencillo visualizar en un golpe de vista la salida resultante del Procedimiento.

Todos estos inconvenientes se evitan con un Data Provider. Aquí el foco está puesto en la salida, razón por la cuál con un solo vistazo quedará evidenciada la estructura del Output. Por otro lado, siendo absolutamente declarativo, nos independizamos de la forma en que se implementa realmente la carga del SDT. De eso se encarga GeneXus.

Cuanto más declarativa sea una herramienta, más fácil de programar, más adaptable al cambio, más independiente de una implementación particular. GeneXus tiende a permitir declarar lo más posible y cada vez programar ‘proceduralmente’ menos. Lo declarativo traslada el problema de la implementación a la herramienta, y se la quita al programador. Cuanto más inteligente una herramienta, menos necesidad tendrá el programador de resolver el problema: le alcanzará con enunciarlo.

Page 264: Aplicaciones Genexus

252

Data ProviderUtilización

• Igual  que  un  procedimiento  que  devuelve  información estructurada:

Parm( in: par1, ..., in: parn, out: &bills ); &TheBills = GetBills( par1, ..., parn)

Procedimiento ‘GetBills’ Objeto GeneXus

Data Provider ‘GetBills’

Parm( in: par1, ..., in: parn);

Output: BillCollection: TrueCollectionName: Bills

Objeto GeneXus

&TheBills = GetBills( par1, ..., parn)

udp

&xml = &TheBills.ToXml()

Un Data Provider también puede recibir parámetros vía regla parm, pero a diferencia de un procedimiento donde todos los parámetros pueden ser de entrada/salida, aquí solo podrán ser de entrada.

Por otro lado, un procedimiento que devuelve información estructurada lo hace mediante una variable que se carga en el código, y que debe declararse como de salida, en el último parámetro de la regla parm.

En un Data Provider, la declaración del tipo de datos de salida se hace mediante las propiedades Output, noen la regla parm.

La invocación desde cualquier objeto GeneXus de un Data Provider es idéntica a la invocación de un procedimiento, es decir, con udp.

Recuerde que al invocar a un objeto y no especificar el método de invocación, se asume udp.

La variable &TheBills deberá estar declarada en el objeto GeneXus en el que se realiza la invocación. Es la variable en la que se devolverá el resultado. Recuerde que si el SDT definido en la KB es el correspondiente a los ítems individuales: Bill, (y no a la colección Bills), entonces la variable &TheBills se definirá como Collection, de tipo de datos Bill.Luego, con la estructura jerárquica devuelta se podrá, por ejemplo, convertir al formato deseado, como XML.

Importante:Como veremos, un Data Provider no solo puede retornar un SDT o colección de SDT, sino también otro tipo, el Business Component, que también representa información estructurada. Vea ese tema para completar el conocimiento de Data Providers.

Page 265: Aplicaciones Genexus

253

Lenguaje de DP

• Componentes básicos:

• Grupos

• Elementos

• Variables

BillsInfo{

Bills{

Bill {

BillDate = &todayCustomerName = CustomerNameBillInvoicePeriodStartDate = &startBillInvoicePeriodEndDate = &endBillAmount = sum( InvoiceAmount, ... )&quantity = &quantity + 1

}}BillQuantity = &quantity

}

El ejemplo que podemos ver aquí es parecido al que estuvimos trabajando. Hemos agregado el elemento BillQuantity. Tómese unos instantes para pensar cómo deberá ser el SDT BillsInfo, para que matchee con este Source. A la izquierda lo hemos presentado.

De todos modos, el Source no tiene por qué escribirse tal cual la estructura del SDT. Cuando en el SDT tenemos un miembro collection de un determinado ítem, podemos omitir del Source el Item como grupo. Ejemplo: con el SDT que tenemos arriba, podríamos haber escrito el Data Provider:

Billsnfo{

Bills{

BillDate = &todayCustomerName = CustomerNameBillInvoicePeriodStartDate = &startBillInvoicePeriodEndDate = &endBillAmount = sum (InvoiceAmount, ... )&quantity = &quantity + 1

}BillQuantity = &quantity

}

con el mismo resultado. GeneXus tiene la inteligencia suficiente como para matchear con el SDT.

Page 266: Aplicaciones Genexus

254

Lenguaje de DPGrupos

• Agrupan tanto elementos, grupos como variables en un mismo nivel de jerarquía.

• Puede ser repetitivo como no serlo (inteligencia para determinarlo). 

BillsInfo{

Bills{

Bill{

…}

}BillQuantity = &quantity

}

BillsInfo{

Bills {

Bill{

BillDate = &todayCustomerName = CustomerName...&quantity = &quantity +1

}} BillQuantity = &quantity

}

Será una colecciónde muchos

Page 267: Aplicaciones Genexus

255

Lenguaje de DPGrupos

• Un grupo repetitivo es análogo a un for each:• Determina tabla base (de igual forma que en un for each)

• Tiene disponibles las mismas cláusulas que para un for each:

BillsInfo{

Bills{

Bill{

BillDate = &todayCustomerName = CustomerNameBillInvoicePeriodStartDate = &startBillInvoicePeriodEndDate = &endBillAmount = sum( InvoiceAmount, ...) &quantity = &quantity + 1}

}BillQuantity = &quantity&quantity = 0

}

[{[order] order_attributesi [when condi]}... | [order none] [when condx]][using DataSelectorName([[parm1 [,parm2 [, ...] ])][{where {conditioni when condi} |{attribute IN DataSelectorName([[parm1 [,parm2 [, ...] ]} }...][defined by att…]

Ver más adelante opciones avanzadas

En el ejemplo, el grupo de nombre Bill será repetitivo. ¿Por qué? Para contestar la pregunta, hagamos otra: ¿y si fuera un for each, donde los elementos de la izquierda de las asignaciones corresponden a los distintos elementos de una variable SDT? En este caso la presencia de CustomerName (a la derecha de la segunda asignación) permite afirmar que hay tabla base: CUSTOMER.

Por tanto el grupo será repetitivo, iterando sobre la tabla CUSTOMER.

En el ejemplo que veníamos trabajando, podíamos tener la cláusula:

Bill using ActiveCustomers()

que es como tener:

For each using ActiveCustomers()

por lo que así no estuviera el atributo CustomerName en la segunda asignación, de todos modos sería con tabla base, por la presencia del atributo CustomerStatus en el Data Selector ‘ActiveCustomers’.

Obsérvese que el grupo de nombre BillsInfo, en cambio, no será repetitivo, no tiene cláusulas asociadas, y los elementos que contiene están definidos a base de variables y no de atributos:

BillQuantity = &quantity&quantity = 0

¿Y qué pasa con el grupo Bills? Obsérvese que en este caso, es un grupo que sólo contiene otro grupo. El grupo contenido será repetitivo, por lo que Bills será una colección de Bill. Por este motivo, el subgrupo Bill podría omitirse (solamente dejar Bills) y que quede implícito. De este modo, las cláusulas del grupo que permiten definir order, filtros, defined by, se pueden asociar a este grupo.

Page 268: Aplicaciones Genexus

256

Lenguaje de DPGrupos

• También pueden repetirse grupos:

Clients{

Client{

Name = ‘Lou Reed’Country = ‘United States’City = ‘New York’

}Client where CountryName = ‘Mexico’{

Name = CustomerNameCountry = CountryNameCity = CityName

}}

El resultado retornado seráuna colección de N+1 ítems: siendo N el número de clientes de México.

Si la condición se hubiese colocado en el grupo Clients, aplicaría a los dos subgrupos Client. Por eso es que se permite que las cláusulas operen a nivel de los grupos que se repiten (items), y no solo a nivel del grupo que es colección de ítems.

Page 269: Aplicaciones Genexus

257

Lenguaje de DPElementos

• Un Elemento es un valor atómico en el Output. 

• Cada Elemento debe ser asignado y su sintaxis es la de las fórmulas. 

Ejemplo:

Clients{

Client{

Name = CustomerNameActive = True if CustomerStatus = Status.Active; False otherwise;

}}

Page 270: Aplicaciones Genexus

258

Lenguaje de DPElementos

• Elementos y Atributos usualmente tienen el mismo nombre notación más compacta:

Ejemplo:BillsInfo{

Bills {

Bill {

BillDate = &today CustomerName = CustomerNameBillInvoicePeriodStartDate = &start...

}}

}

BillsInfo{

Bills{

Bill {

BillDate = &todayCustomerNameBillInvoicePeriodStartDate = &start...

}}

}

Page 271: Aplicaciones Genexus

259

Lenguaje de DPVariables

• Algunas veces es necesario realizar cálculos internos:

Ejemplo:

BillsInfo{

Bills{

&quantity = 0Bill {

BillDate = &todayCustomerNameBillInvoicePeriodStartDate = &startBillInvoicePeriodEndDate = &endBillAmount = sum( InvoiceAmount, ... )&quantity = &quantity + 1

}}BillQuantity = &quantity

}

Page 272: Aplicaciones Genexus

260

Lenguaje de DPGrupos: Opciones avanzadas

• Cláusula Default (~ When none)• el grupo solo irá a la salida si el grupo precedente (de igual nombre) no está

presente. 

• Cláusulas de Paginado: Count y Skip• Para manejar cuántos registros irán a la salida.

• Cláusula NoOutput• en un Grupo significa que el grupo no deberá estar presente en la salida, sino solo 

sus elementos subordinados.

• Cláusula OutputIfDetail• Para grupo cabezal conteniendo grupo con sus líneas: solo se presenta el primero en 

la salida si tiene líneas.

• Cláusula Input• si se necesita trabajar con colecciones (devueltas por Procedimiento o Data Provider) 

como Input del DP.

http://wiki.gxtechnical.com/commwiki/servlet/hwiki?Data+Provider+Language

Podrá encontrar la información completa de este tema en inglés en nuestro community wiki, en la siguiente página:

http://wiki.gxtechnical.com/commwiki/servlet/hwiki?Data+Provider+Language

Page 273: Aplicaciones Genexus

261

Lenguaje de DPGroup: cláusula Default

• Cláusula Default: el grupo solo irá a la salida si el grupo precedente (de igual nombre) no está presente.(~ When none en for each)

CurrentTaxesWhere TaxInitialDate >= today()Where TaxFinalDate <= today(){

VAT = TaxVATIncome = TaxIncome

}CurrentTaxes [Default]

{VAT = 0.7Income = 0.3

}

TaxInitialDate*TaxFinalDate*TaxVATTaxIncome

Tabla TAXES

Sólo se incluye en el Output si no se encontró registro en el día de hoy

Page 274: Aplicaciones Genexus

262

Lenguaje de DPGrupos: cláusulas de paginado

• Count y Skip. 

• Para manejar cuántos registros irán a la salida.

Customers{

Customer [Count = 20] [Skip = 100] {

Code = CustomerIdName = CustomerName

}}

Se saltean los primeros 100 customers y se incluyen en el Output los 20 siguientes.

Page 275: Aplicaciones Genexus

263

Lenguaje de DPGrupos: cláusula NoOutput

• En un Grupo significa que el grupo no deberá estar presente en la salida: sino solo sus elementos subordinados.

Employees{

Employee{

Id = EmployeeIdName = EmployeeNameEarningInfo [NoOutput]Where IsAutorized(&UserId){

Salary = EmployeeSalaryBonus = EmployeeBonus

}}

}

<Employees><Employee>

<Id>123</Id><Name>John Doe</Name><EarningInfo>

<Salary>30000</Salary><Bonus>5000</Bonus>

</EarningInfo></Employee>...

</Employees>

<Employees><Employee>

<Id>123</Id><Name>John Doe</Name><Salary>30000</Salary><Bonus>5000</Bonus>

</Employee>...

</Employees>

…en lugar de…

Page 276: Aplicaciones Genexus

264

Lenguaje de DPGrupos: cláusula OutputIfDetail

• Cada ítem de la colección de salida tiene un cabezal y algunas líneas: cláusula a nivel del grupo cabezal  sólo se presentarán en la salida aquellos grupos que tengan líneas.

Countries{

Country [OutputIfDetail]{

Id = CountryIdName = CountryName

Customers{

Id= CustomerIdName = CustomerName&quantity = &quantity + 1

}Quantity = &quantity

}}

Si un país no tiene clientes asociados no aparecerá como ítem de la colecciónCountries en la salida.

Tabla base: COUNTRY

Tabla base: CUSTOMER

No lo hemos mencionado, pero como intuitivamente podemos pensar, de tener un par de grupos “anidados”(un grupo que, entre otras cosas, contiene a otro), si cada uno debe acceder a la base de datos, entonces las tablas base, así como el criterio de navegación se determinan exactamente igual que en el caso de un par de for eachs anidados.

Por ese motivo, en el ejemplo, el grupo Country tiene tabla base COUNTRY; el grupo Customers tiene tabla base CUSTOMER, y se hará un join entre ambas tablas a la hora de recuperar la información para cargar la colección de países. Es decir, por cada registro de COUNTRY se cargará la información de sus atributos CountryId y CountryName en los elementos Id y Name del ítem Country del SDT colección “Countries” que se está cargando, y luego se recorrerá la tabla CUSTOMER filtrando por aquellos registros para los cuales CUSTOMER.CountryId = COUNTRY.CountryId, cargando para cada uno los elementos Id y Name.

La presencia de la cláusula OutputIfDetail hace que solamente se presenten en la salida aquellos países que cuenten con clientes asociados. Si un país de la base de datos no tiene cliente alguno, entonces no se presentará como item de la colección de salida, “Countries”.

Page 277: Aplicaciones Genexus

265

Lenguaje de DPCláusula Input

• Hasta aquí asumimos que el Input venía de la BD; pero también se necesitan otro tipo de entradas. Por ejemplo, la salida de unProcedimiento o Data Provider.  La forma obvia de trabajo es a través de variables, que una vez asignadas se manejan de forma usual:

• Pero  si  se  necesita  trabajar  con  una  colección  se  necesita  la cláusula Input…

&var = Proc.udp( parm1, ..., parmn)

&SdtVariable = DataProvider( parm1, ..., parmn )

Page 278: Aplicaciones Genexus

266

Lenguaje de DPCláusula Input

• Para trabajar con colecciones.

VerySimple{

Month Input &i = 1 to 12{

MonthNumber = &i}

}

CustomersFromAnotherDataProvider{

&CustomersSDT = GetCustomers() // a DataProvider that Outputs Customers collectionCustomer Input &Customer in &CustomersSDT{

Id = &Customer.CodeName = &Customer.Name

}}

Similar al ‘For &i=1 to 12’del lenguaje procedural

Otro Input puede ser un SDT collection:

Similar al ‘For &var in Expression’del lenguaje procedural

Page 279: Aplicaciones Genexus
Page 280: Aplicaciones Genexus

267

Actualización de la Base de Datos

Page 281: Aplicaciones Genexus

268

Actualización BDInsert-Update-Delete

• Actualización interactiva: • Transacciones: 

• A través del form el usuario ingresa/modifica/elimina los datos.

• Ventajas: • Se ejecutan las reglas del negocio (y no se actualiza registro que violeregla Error especificada)

• No se actualiza registro que viole integridad referencial.

• Business Components  (BC)

• Actualización no interactiva:• Business Components  (BC)

• Procedures

Hasta aquí sólo conocemos una forma de actualizar la base de datos de nuestra aplicación: las transacciones.Como sabemos, una transacción determina la o las tablas requeridas para almacenar su información. A su vez, al ser generada, se convertirá en un programa que implementa la lógica de inserción, eliminación y modificación de datos en esas tablas, en forma totalmente transparente para el programador. También la transacción permite definir todas las reglas de negocio que deberán cumplir los datos asociados. El programa generado se encarga de ejecutarlas. Así, si en una transacción tenemos una o varias reglas Error, que se disparan al satisfacerse determinadas condiciones, esas reglas estarán incluidas en el código generado, y no se permitirá actualizar la base de datos hasta tanto las condiciones que disparan esas reglas dejen de satisfacerse para los datos que se están manejando en esa oportunidad.Asimismo, como vimos, las transacciones aseguran el control de integridad referencial, muy importante para asegurar la consistencia de la base de datos.

Pero las transacciones no cubren todas las necesidades en cuanto a la actualización de datos. También se necesitará una forma no interactiva, batch, de realizar actualizaciones sobre tablas.

Para ello existen dos alternativas: actualización utilizando lo que se conoce como Business Component, absolutamente relacionado con las transacciones, o utilizar comandos específicos para tal fin dentro de objetos de tipo Procedure.

Luego veremos que los Business Components permiten gran flexibilidad, dado que permiten actualizar la base de datos de cualquier forma: tanto interactiva como no interactivamente.

En lo que sigue introduciremos los Business Components y luego los comandos de actualización directa dentro de Procedimientos.

Page 282: Aplicaciones Genexus

269

Business ComponentsEscenario

• Necesitamos registrar los recibos que efectuamos a nuestros clientes.

Rules:Default( BillDate, &today);Error( ‘The invoice period considered must be past’ ) ifBillInvoicePeriodEndDate > BillDate;Error( ‘Wrong invoice period’ ) ifBillInvoicePeriodStartDate > BillInvoicePeriodEndDate;

Pero este es un caso en el que no nos sirve la transacción, dado que la generación de recibos es una tarea batch: se lanza una vez al mes un proceso que calcula y registra todos los recibos correspondientes a las facturas dentro de determinado período.

autonumber

Page 283: Aplicaciones Genexus

270

Business ComponentsEscenario

Bill {

BillDate = &todayCustomerIdBillInvoicePeriodStartDate = &startBillInvoicePeriodEndDate = &endBillAmount = sum( InvoiceAmount, InvoiceDate >= &start and InvoiceDate <= &end and

InvoicePendingFlag )}

parm( in: &start, in: &end);Output: BillCollection: TrueCollection Name: Bills

• Ya teníamos declarado el Data Provider ‘GetBills’ que realizaba el proceso de cálculo de recibos deseado, pero no grababa:

Y nos devolvía una colección de tipos de datos estructurados (SDT). Si observamos, la estructura jerárquica de este DP es casi idéntica a la estructura de la transacción Bill...

Page 284: Aplicaciones Genexus

271

Business ComponentsEscenario

• ...¿y si pudiéramos guardar en una estructura los datos y luego grabarlos en la base de datos?

Bill

Bill

Bills

1000BillAmount

......

2516CustomerId

12/12/08BillDate

750BillAmount

......

158CustomerId

12/12/08BillDate

For &bill in GetBills( &start, &end )&bill.Save()

endfor

¿y si además esta grabación se realizara ejecutando las mismas reglas que se ejecutan cuando se graba mediante la transacción Bill, y controlando además la integridad referencial?

¡&bill no será una variable de tipo SDT, sino Business Component!

Page 285: Aplicaciones Genexus

272

Business ComponentsBC

• A  partir  de  una  transacción,  se  puede  crear  su  Business Component (BC). 

Permite encapsular la lógica de la transacción (reglas, eventos, controles de integridad referencial, estructura de los datos) de manera de poder realizar inserciones,modificacionesy eliminaciones, sin necesidad del form...

Se creará automáticamente en la KB un tipo de datos Business Component, que podrá asociarse a variables, y cuyo nombre será el de la transacción.

Por defecto la propiedad Business Component estará apagada. Eso significará que la lógica de negocio dada por la transacción, solo se utilizará dentro de la propia transacción, y no se creará un tipo de datos de igual nombre que la transacción, Bill, que permita encapsular la lógica de la transacción para utilizarla desde otros objetos.

Page 286: Aplicaciones Genexus

273

Business Components

En cualquier objeto GeneXus (ej: un procedimiento):La variable &bill tendrá la misma estructura que el SDT obtenido a partir de la transacción, y se trabaja de forma análoga, pero además ofrecerá métodos para actualizar la base de datos en función de esos valores.

&bill.BillInvoicePeriodStartDate = #10-10-08#&bill.BillInvoicePeriodEndDate = #09-10-08# &bill.Save()

¿Se insertará registro en la tabla BILL?

Obsérvese que en este caso la fecha inicial corresponde al día 10 de octubre, mientras la fecha final corresponde al día 9 de octubre... es decir, la fecha inicial será posterior a la fecha final...

Page 287: Aplicaciones Genexus

274

Business ComponentsInsert

&bill.CustomerId = 3456&bill.BillInvoicePeriodStartDate = #10-10-08#&bill.BillInvoicePeriodEndDate = #09-10-08# &bill.Save()

¿Qué pasaría en la transacción si intentáramos grabar con estos datos?

Default( BillDate, &today);Error( ‘The invoice period considered must be past’ ) if BillInvoicePeriodEndDate > BillDate;Error( ‘Wrong invoice period’ ) if BillInvoicePeriodStartDate > BillInvoicePeriodEndDate;

10/10/08 09/10/08>¡No se insertará!

Obsérvese que se llenan algunos miembros de la estructura de la variable &bill, Business Component, y luego se ejecuta el método Save (inexistente en SDTs).

Esto es equivalente a lo que en forma interactiva ocurriría si el usuario final ingresa esos mismos valores en los atributos correspondientes del form de la transacción, y luego presionara el botón ‘Confirm’.

Por tanto, al igual que como ocurre con la transacción, deberán dispararse las reglas y realizarse los controles de integridad referencial. ¿Qué pasará con ese juego de datos si se intenta grabar mediante la transacción? Se impedirá la grabación, debido a que se está cumpliendo la condición de la segunda regla de error (también podría cumplirse la de la primera si la fecha de hoy fuera anterior al 10 de setiembre de 2008). Por otro lado, si no existiera en la tabla CUSTOMER un cliente con identificador 3456, fallará la integridad referencial y así tampoco se dejaría ingresar el registro en la tabla BILL de base de datos.

Page 288: Aplicaciones Genexus

275

Business ComponentsInsert

&bill.CustomerId = 3456&bill.BillInvoicePeriodStartDate = #09-10-08#&bill.BillInvoicePeriodEndDate = #10-10-08# &bill.Save()

¿Y ahora que los datos no violan reglas y suponiendo que el cliente 3456 existe y &today>10/10/08?

¡Se insertará registro en tabla BILL!

¿Con qué valores de BillId, BillDate y BillAmount?

BillId era autonumber...BillDate = &today... se dispara regla DefaultBillAmount vacío... no hay regla

¿y CustomerName?

Antes de ejecutar el método Save del Business Component, el valor de BillId en la estructura de &billserá vacío. Sin embargo, una vez que se ejecute el Save, como el atributo BillId era autonumber en la tabla BILL, se ejecutará la propiedad a nivel de la tabla y el registro se insertará con el número siguiente al último dado.

En el caso de BillDate, análogamente, como no se le asigna valor en la estructura de &bill, antes del Save estará vacío, pero cuando éste se ejecute, se disparará la lógica de la transacción, y en particular la regla Default( BillDate, &today ) declarada. Por tanto en el registro insertado en la base de datos, el valor del atributo BillDate corresponderá a la fecha de hoy.

Para BillAmount podríamos hacer el mismo análisis. Pero a diferencia del caso anterior, no hay regla que le asigne valor, por lo cuál se insertará el registro con valor vacío en este atributo.

De asignarse valor para &bill.CustomerName no será considerado a la hora de la inserción, dado que CustomerName es un atributo inferido, y no tiene regla Update que permita modificarlo.

Lo mismo sucedería para atributos definidos a nivel de la estructura de la transacción pero que fueran fórmulas. Es decir, son atributos virtuales en la transacción, por lo que también lo son a nivel del Business Component. Se disparará su valor.

Page 289: Aplicaciones Genexus

276

Business ComponentsUpdate-Delete

&bill.Load( 100 ) &bill.BillDate = #06-01-08#&bill.CustomerId = 1258 &bill.Save()

¿Y si lo que deseo es actualizar un registro, no insertar uno nuevo?

¡Se actualizará registro 100 de tabla BILL!(siempre que exista cliente 1258 y06/01/08>=BillInvoicePeriodEndDate)

¿Y para eliminar el recibo 100? &bill.Load( 100 ) &bill.Delete()

¡Se realizará siempre y cuando no exista ninguna tabla que referencie al Bill 100!

Page 290: Aplicaciones Genexus

277

enum

Business ComponentsManejo de errores

&bill.Load( 100 ) &bill.BillDate = #06-01-08#&bill.CustomerId = 1258 &bill.Save()

En transacciones vemos los errores interactivamente (y en el Error Viewer).¿Cómo nos enteramos de los errores o mensajes resultantes de un intento de actualización vía BC?

Tenemos los métodosBooleanos:

&bill.Fail() &bill.Success()

Y en caso de falla (por regla Error, falla de IR o de duplicados) y/o de reglas Msg podemos obtener la lista de mensajes de advertencia o de error:&messages = &bill.GetMessages()

de tipo predefinido SDT... Warning

Error

Para manejar los errores habrá que definir una variable de tipo de datos SDT predefinido (viene con la KB) Messages (collection).

Cuando se ejecutan los métodos: Save, Check, Load, Delete se disparan y cargan los mensajes generados automáticamente por GeneXus así como las reglas Msg y Error definidos en la transacción. Se recomienda que siempre se recupere la lista de estos mensajes y se haga un “manejo de errores”.

Los mensajes más comunes generados automáticamente por GeneXus son:

Las reglas Msg y Error aceptan en su definición además del parámetro con el mensaje a desplegar, un segundo parámetro que define el Identificador del mensaje. El objetivo es que cuando se ejecute la transacción como Bussiness Component, y se obtenga la lista de mensajes ocurridos luego de ejecutaruna acción sobre la base de datos, se tenga de cada mensaje, además del mensaje en sí, su identificador, siendo posible así evaluar el identificador del mensaje para codificar el comportamiento en consecuencia:

Msg|Error(<mensaje>, <Id del mensaje>)

Ejemplos de <Id del mensaje>: "1", "2", "Error1", "Error2" o una descripción como ser "CustomerNameCannotBeEmpty", etc.

De no especificar un identificador para el mensaje, habrá que preguntar por el texto del mensaje.Nota: Para los mensajes generados automáticamente por GeneXus, el Id es siempre en Inglés (independientemente del idioma seleccionado en el modelo).

Page 291: Aplicaciones Genexus

278

Business ComponentsCaso de uso

¡Data Provider tiene como output una colección de Business Component Bill!

Business Component omite valor depropiedad ‘Commit on Exit’ de la transacción:¡hay que utilizar comando Commit/Rollbacken forma explícita!

Necesitamos pasar a ‘False’ atributo InvoicePendingFlag de invoices facturadas...

Aquí completaríamos el proceso de generación de recibos.

Observemos primeramente un hecho importante: un data provider no solo puede devolver un SDT simple o colección, sino también un BC simple o colección.Importante: el BC devuelto solo podrá insertarse en la base de datos. Es decir, un Data Provider solo permite llenar su estructura, para luego hacer una operación de INSERT sobre la base de datos. No será posible hacer una actualización o eliminación con un BC cargado vía Data Provider.

Obsérvese por otro lado cómo se ha definido la variable &message de tipo de datos Messages.Message, correspondiente a los ítems del SDT predefinido Messages devuelto por el método GetMessages del BC.

Una vez que hemos obtenido e ingresado en la tabla BILL todos los recibos correspondientes a la facturación, deberíamos recorrer las facturas procesadas, y modificar el valor de su atributo InvoicePendingFlag, pasándolo a False. Recordemos que el valor de este atributo se utiliza para no procesar dos veces una misma factura. Recordemos que este valor se utiliza en el Data Provider en el cálculo del elemento BillAmount:

sum( InvoiceAmount, InvoiceDate >= &start and InvoiceDate <= &end and InvoicePendingFlag )

Dejaremos pendiente esta última parte para cuando estudiemos, unas páginas más adelante, las formas de actualización directa ( dentro de procedimientos exclusivamente ), de los registros de las tablas.

Page 292: Aplicaciones Genexus

279

Business ComponentsOtra opción

Este objeto es del tipo Web Panel. Lo utilizamos para pedirle al usuario final el período de facturación

&start

&end

Desde un Web Panel también puede utilizarse un BC para actualizar la base de datos

Adelantándonos aquí a presentar el otro tipo de objeto interactivo que estudiaremos un poco más adelante, el Web Panel, mostramos un objeto de este tipo en ejecución. Su función será pedir al usuario final un par de valores, que almacenará en las variables correspondientes de tipo Date (&start y &end) y luego, cuando el usuario presione el botón asociado al Evento Enter del Web Panel, se ejecutará su código.

Obsérvese que el código es idéntico al del procedimiento visto antes. Con este ejemplo pretendemos mostrar que mediante un Business Component puede actualizarse la base de datos desde cualquier objeto GeneXus.

Page 293: Aplicaciones Genexus

280

Business ComponentsCaso de uso interactivo

• Problema: se inserta país solo si se tiene cliente nuevo del mismo y no puede quedar país sin cliente en el sistema.

commit automático

1

2

3¿si se cae el sistemaaquí?

Recordemos que no se puede armar una sóla UTL con dos transacciones.¿Entonces?

4 commit automático

Supongamos que cada vez que se inserta un nuevo país en el sistema, es necesariamente debido a que se tiene un nuevo cliente de ese país. Supongamos que como requerimiento, además, no debe quedar bajo ninguna circunstancia ingresado un país sin por lo menos un cliente asociado.

Tal como tenemos implementada la aplicación, esto no se está controlando. ¿Cómo se ingresa un país y un cliente para el mismo? El usuario debe ejecutar la transacción Country, ingresar el país. Luego abrir la transacción Customer, e ingresar los datos del cliente y confirmar. ¿Pero qué sucederá si se cae el sistema cuando se está ingresando el cliente? Quedará el país ingresado (recordar que cada transacción por defecto hace commit al final).

Page 294: Aplicaciones Genexus

281

Business ComponentsCaso de uso interactivo

• Solución: en la transacción Country, crear variable &customer de tipo BC Customer e insertarla en el Form y agregar regla Accept. 

Commit automático

&customer.CountryId = CountryIdon AfterInsert;

&customer.Save() on AfterInsert;msg( ‘It fails’) if &customer.Fail()

on AfterInsert;

1 2

3

Desventaja: no se dispararán en forma interactiva las reglas asociadas a Customer...

Necesitamos que la inserción del país en la tabla COUNTRY y la inserción del cliente en la tabla CUSTOMER se realicen dentro de una misma UTL. Como hemos visto, las operaciones efectuadas por dos transacciones no pueden incluirse en una única UTL. Por esta razón, necesitaremos hacer la inserción dentro de la misma transacción.¿Cómo? Dentro de la transacción Country, definimos una variable &customer, de tipo businesscomponent Customer (para ello, tendremos previamente que haber prendido la propiedad Business Component de la transacción Customer, de manera tal que se cree este tipo de datos en la KB). Una vez efectuado esto, simplemente insertando en el form la variable (al igual que sucedía con un SDT), GeneXus colocará controles para cada uno de los miembros de la estructura: &customer.CustomerId, &customer.CustomerName, &customer.CustomerAddress, etc.

Las variables por defecto en las transacciones son de salida, por lo que habrá que especificar regla Accept para que puedan ser de escritura en ejecución y el usuario pueda ingresar valores para las mismas.

El Save del customer deberá realizarse necesariamente luego de insertarse el país en su tabla (de lo contrario fallará la integridad referencial). Por tanto en las reglas:

&customer.Save() on AfterInsert;

Sabemos que en este momento ya se habrá grabado el registro correspondiente al país, y luego vendráeste Save... a continuación, el commit automático.

Page 295: Aplicaciones Genexus

282

Business ComponentsResumen

• Objetivo: • Reutilizar la lógica del negocio definida en las transacciones. Usar el 

poder de las transacciones (sin sus forms) desde otros objetos GeneXus:• Procedimientos, Web Panels... 

• desde otra Transacción (al igual que una variable podía llenarse interactivamente insertándola en el Form, también un BC)

• Beneficios: • Actualización a la BD garantizando integridad de los datos y ejecución de 

las reglas del negocio.

• Reutilización de código (no necesidad de duplicar reglas de negocio)• Varios objetos GeneXus pueden actualizar la BD.

Page 296: Aplicaciones Genexus

283

Business ComponentsReglas y Eventos

• Reglas: son ejecutadas todas las reglas de la transacción excepto (son ignoradas por el especificador):• las que incluyen user interface ( Ej: Customer.call(), 

• las que no aplican: parm, prompt, NoPrompt, Default_mode, etc

• Eventos: todos los eventos de la transacción son ignorados, excepto los eventos Start y After TRN (y si éstos incluyen referencias a objetos con user interface, se ignoran). 

Nota: cuando decimos ‘se ignora’ nos referimos en el contexto de la actualización utilizando BC, no cuando la actualización se realiza a través de la propia transacción.

Si existe una regla que invoca a un objeto que tiene interfaz, es decir, form, esa regla no se incluye en el BC. Existe una forma de especificar que una regla declarada en la transacción no aplique cuando se ejecuta la transacción, sino solo cuando se ejecuta el Business Component asociado: es calificando la regla con [BC].

Ejemplo:

[BC] Default( BillDate, &today);

Si se quiere calificar de una sola vez un conjunto de reglas:

[BC]{

regla1;regla2;...reglan;

}

Lo mismo vale para eventos.

Análogamente, existen calificadores para indicar que una regla solo se ejecute si se está corriendo la transacción con su form web: [WEB].

Page 297: Aplicaciones Genexus

284

Actualización no interactiva directa

Procedimientos

Page 298: Aplicaciones Genexus

285

ProcedimientosUpdate

• No hay un comando específico para modificar un registro: se realiza en forma implícita dentro del comando For each. 

Ejemplo:

parm( in: CustomerId, in: &StartDate, in: &EndDate);

La modificación de datos de la base de datos se realiza en forma implícita: no hay un comando específico de actualización.

Para actualizar uno o varios atributos de una tabla se utiliza el comando For each, y dentro del mismo el comando de asignación.

Se pueden actualizar varios atributos dentro del mismo For each, pudiendo éstos pertenecer tanto a la propia tabla base como a la tabla extendida.

El ejemplo que presentamos completa el que habíamos iniciado respecto al proceso de facturación.

Obsérvese que aquí se está recorriendo la tabla INVOICE, filtrando por InvoiceDate, por InvoicePendingFlag, así como por CustomerId (en el listado de navegación se observará que si bien no se ha especificado order, al recibir en el atributo CustomerId, que es foreign key, se ordena por este atributo para optimizar). Dentro del for each, para cada factura que cumple las condiciones, se actualiza el valor del atributo InvoicePendingFlag. Aquí podrían actualizarse no solo ese atributo, sino cualquiera de la propia tabla INVOICE, o de su extendida, con las excepciones que se indican a continuación.

Page 299: Aplicaciones Genexus

286

ProcedimientosUpdate

• Atributos actualizables: los de la tabla extendida del For each. Salvo:• los que forman parte de la clave primaria de la tabla base.

• los que forman parte del índice por el que se está accediendo a la tabla.

• La actualización se realiza en el Endfor.

• No se controla integridad referencial. • Si se actualiza un atributo que es FK  no se controla existencia.

• Sólo se realiza control de duplicados:  For each ...bloque1

[when duplicatebloque2...]

Endfor

Si dentro de for each se intenta actualizar un atributo para el que hay definido índice unique, y existe duplicado el valor, no se actualiza... de existir cláusula when duplicate se ejecuta su código.

Supongamos que tenemos el siguiente diagrama de Bachman genérico:

Y en el Source de un procedimiento hacemos:For each

C = &CE = &ED = &D

Endfor

Aquí la tabla base del For each será claramente la de clave primaria A y dentro del For eachestamos actualizando tanto atributos de la propia tabla base como de la extendida. ¿En quémomento ocurre efectivamente la actualización de los registros involucrados?La actualización no ocurre ni bien se encuentra un comando de asignación dentro del For each, sino luego de que se encuentran todos, para cada instancia de la tabla base, es decir, cuando se llega al Endfor para cada iteración.

Como vimos antes, no podemos actualizar dentro del comando For each atributos de la clave primaria. Sin embargo podríamos querer actualizar un atributo que sin ser clave primaria, estádefinido como clave candidata (mediante un índice unique). Si el atributo es clave candidata, debe controlarse que no se dupliquen sus valores, por lo que de encontrarse duplicado el registro en este sentido, no se permitirá hacer la actualización.Si se desea tomar una acción en caso de que esto ocurra, el comando For each agrega la cláusula when duplicate. Solo tiene sentido si existe alguna clave candidata para ese Foreach.

A*BCD

B*EF

Page 300: Aplicaciones Genexus

287

ProcedimientosUpdate

• Eficiencia:

• Actualización masiva: cláusula Blocking reduce número de accesos a la BD.

for eachwhere InvoiceDate >= &StartDatewhere InvoiceDate <= &EndDate

InvoicePendingFlag = Falseendfor

¿Si hay un millón de registros a actualizar?

Por cada uno se envía comando UPDATE al servidor de BD (que no tiene por quéestar en la misma máquina que el Web Server) ¿eficiencia?

for eachwhere InvoiceDate >= &StartDatewhere InvoiceDate <= &EndDateBlocking 1000

InvoicePendingFlag = Falseendfor

Hasta la N-ésima (1000) iteración, el Updatese realiza en un buffer. Con la N-ésima se envía comando: Update masivo a la BD y se actualizan los datos del buffer.

Realizar un “blocking” a las operaciones de actualización de la BD significa almacenarlas en memoria y enviarlas en grupo al DBMS. En lugar de interactuar con el DBMS en cada operación de actualización, la interacción tiene lugar solamente cada N operaciones de actualización, donde N es el número que se establece en la cláusula Blocking.

No será el caso de nuestro ejemplo, pero ¿qué sucedería si se está haciendo una actualización masiva que incluye algún atributo clave candidata de la tabla, y se encuentran duplicados para algunos de los registros del grupo de 1000 que se está procesando?

En ese caso, una vez llenado el buffer con las 1000 actualizaciones, al enviar a la BD el comando UPDATE del grupo, saltará el error de duplicados y se iterará sobre el grupo, realizando un comando UPDATE individual de BD, uno por uno.

Page 301: Aplicaciones Genexus

288

ProcedimientosDelete

• Para eliminar registros de una tabla: Comando Delete.

• Debe ir dentro de un For each.

• Elimina el registro de la tabla base en el que se esté posicionado.

• Se ejecuta ni bien se encuentra el comando (y no en el Endfor).

• No controla integridad referencial.

Ejemplo:

For eachdefined by InvoiceDateBlocking 1000

DeleteEndfor

Elimina todos los registros de la tabla base: INVOICE, eliminándolos en grupos de a 1000 (para hacerlo más eficientemente).Las líneas quedarán ‘colgadas’

Para eliminar datos se utiliza el comando Delete dentro del comando For each.

El comando Delete elimina el registro en el que se está posicionado en un momento dado. Es por ello que no puede aparecer “suelto” dentro del Source. Debe colocarse dentro de un comando For each, cuya tabla base sea la tabla de la que se quieren eliminar registros. Solo se eliminan los registros de la tabla base, no de la extendida.

Si deseamos eliminar todas las facturas anteriores a una fecha dada, podemos programar un procedimiento:

For eachwhere InvoiceDate <=&date

For eachdefined by InvoiceDetailQuantity

DELETE //se eliminan las líneasEndforDELETE //luego de eliminar las líneas se elimina el cabezal

Endfor

Para mayor eficiencia en la eliminación, dependiendo del número de registros de la base de datos, convendrá agregar cláusula Blocking con un factor de bloqueo, N, adecuado. Por ejemplo, si se agrega “Blocking 1000” la eliminación física no se realizará en cada iteración, sino que cada 1000 veces que se llegue al Endfor, se eliminarán el grupo de 1000 registros en un único acceso a la Base de Datos (en lugar de 1000).

Page 302: Aplicaciones Genexus

289

ProcedimientosInsert

• Comando New: permite insertar un registro en una tabla.

• No controla integridad referencial.

• Realiza el control de duplicados: 

NewProductId = &ProductIdProductPriceListDate = &todayProductPriceListPrice = &price

endnew

Procedimiento “NewPrice”

NewProductId = &ProductIdProductPriceListDate = &todayProductPriceListPrice = &price

when duplicatefor each

ProductPriceListPrice = &priceendfor

endnew

¿Si ya existe registro para el producto y fecha? actualizar el precio: cláusula when duplicate.

Supongamos que queremos implementar un procedimiento que haga lo siguiente: para el producto cuyo código es recibido por parámetro, dé de alta un nuevo precio (también recibido por parámetro) en su lista de precios, para la fecha correspondiente al día en que se ejecuta el procedimiento. Este debe crear un nuevo registro en la tabla PRODUCTPRICELIST, que estácompuesta por los atributos ProductId, ProductPriceListDate y ProductPriceListPrice, siendo su clave primaria una compuesta, conformada por ProductId y ProductPriceListDate.

Para ello se utiliza el comando new que escribimos arriba. Observemos que dentro del mismo aparecen comandos de asignación, donde se le da valor a los atributos de la tabla en la que sequiere insertar el registro.

Cada vez que GeneXus encuentra un new, debe determinar la tabla en la que se realizará la inserción (tabla base del new). Es determinada a partir de los atributos que aparecen dentrodel comando new, del lado izquierdo en una asignación.

El único control que realiza, es el de duplicados. En nuestro caso, si existiera un registro con los valores de ProductId y ProductPriceListDate, no se realizará la inserción (pero en cambio si lo que no existiera fuera un producto en la tabla PRODUCT con el ProductId, allí sí se insertará, pues no controla integridad referencial). Si se programa la cláusula when duplicate, se actualizará el registro encontrado.

Observemos que para realizar la actualización del atributo, la asignación debe estar dentro de un comando For each. Si no colocamos el For each no se realizará la actualización del precio para ese registro, es decir, es como si no se hubiera incluido cláusula when duplicate.

Si se quisiera insertar un registro para el cual existiera clave candidata duplicada, también se controlará y no se realizará la inserción. En caso de existir cláusula when duplicate, se ejecutará.

Page 303: Aplicaciones Genexus

290

ProcedimientosInsert

• Ejemplo: si quisiéramos realizar la generación de recibos directamente en un procedimiento (no a través de BC).

For each using ActiveCustomers()NewBlocking 1000

BillDate = &TodayBillInvoicePeriodStartDate = &startBillInvoicePeriodEndDate = &endBillAmount = sum( InvoiceAmount, InvoiceDate >= &start and

InvoiceDate <= &end andInvoicePendingFlag )

Endnewendfor

En el for each se recorren los clientes activos y el new inserta en la tabla BILL un nuevo recibo para ese cliente(¿por quéCustomerId no aparece asignado?).

Si los clientes son miles, puede optimizarse la inserción y hacerse en bloques.

El caso más común será tener el comando new dentro de un for each, dado que en general se quieren insertar registros en base a cálculos efectuados en función de otros.

El mismo proceso de generación de recibos que habíamos resuelto anteriormente utilizando Data Provider y Business Component, podríamos realizarlo con un procedimiento que utilice el comando new de inserción. ¿Cuál alternativa elegiría usted? Recuerde que con los comandos de actualización dentro de procedimientos, el único control que se realiza es el de duplicados.

Si las inserciones son muchas, así como vimos para el caso de las actualizaciones, disponemos de la cláusula blocking para ir guardando en un buffer y luego hacer la inserción de todos esos registros a la vez.

En nuestro caso no fallará la inserción, debido a que la clave primaria es autonumber, y que no tenemos claves candidatas (vía índices unique) en la tabla de recibos (BILL).

Pero si no fuera el caso, como las inserciones se van realizando en el buffer hasta llegar a la 1000, no es posible hasta completar el buffer saber si alguna operación fallará. Cuando se ejecuta el INSERT masivo de base de datos, allí sí puede fallar alguna inserción. En ese caso, se itera en los elementos del buffer, ejecutando el INSERT simple, uno por uno. Si existe cláusula When duplicate en el New, entonces por los registros que fallen, se ejecutará la cláusula.

Page 304: Aplicaciones Genexus

291

ProcedimientosInsert

• Sintaxis del new

new[ Defined by att1,…, attN ][ Blocking NumericExpression ]

bloque_asignaciones1[ when duplicate

For eachbloque_asignaciones2

Endfor ]endnew

deben pertenecer a una tabla física

tabla base

att1,…, attN

attx1 = ......attxm = ...

Nota: No es necesario asignar valor a todos y cada uno de los atributos de la tabla. Algunos vienen instanciados por el contexto del new (ej: si está dentro de un for each) y no es necesario asignarles valor para el registro a insertar (toman el del contexto).

En la sintaxis presentada, bloque_asignaciones1 es un bloque de código compuesto mayormente por sucesivos comandos de asignación (aquí se asigna valor a los atributos de la tabla en la que se insertará el registro, aunque también pueden asignarse valores a variables, así como anidarse otro comando new).

La cláusula Defined By opcional, se incorpora a los mismos efectos que lo hacía para el comando For each: ayudar a determinar la tabla base.

La tabla base del new se obtiene de los atributos del Defined By y los que aparezcan del lado izquierdo de asignaciones dentro del bloque_asignaciones1. Aquí no se utiliza la tabla extendida.

En el caso de que el comando new esté dentro de una cláusula repetitiva (ej. For each), es posible reducir el número de accesos a la base de datos usando la cláusula blocking.

El comando new realiza un control de duplicados, de manera tal que no se permitirá insertar un registro que ya exista en la tabla.

La cláusula when duplicate del comando permite programar la acción en caso de que el registro ya exista en la tabla base (tanto por clave primaria como por clave candidata).

Normalmente, de ocurrir lo anterior, se quiere actualizar algunos de los atributos de dicho registro. Para ello, en bloque_asignaciones2 se realizan tales asignaciones, pero como lo que se hace es actualizar un registro (y no insertar uno nuevo), estas asignaciones aparecen rodeadas de “For each – Endfor”, pues como hemos visto, las actualizaciones solo pueden realizarse dentro de un For each.

De no especificarse cláusula when duplicate para un new, si el registro que quiere insertarse se encuentra duplicado no se realizará acción alguna y la ejecución continuará en el comando siguiente. Es decir, como no puede insertar el registro porque ya existe uno, no hace nada y sigue adelante, con el próximo comando.

Page 305: Aplicaciones Genexus

292

Actualización BDBC versus Proc

• Actualización vía Business Component:• Se realizan controles de integridad referencial.• Se controlan duplicados.

• Se disparan las reglas del negocio.

• Actualización vía comandos en procedimientos:• No se realiza control de integridad referencial.

• El único control que se realiza es el de duplicados.

• No tiene ninguna relación con transacción aquí no hay reglas.

-

+

En los procedimientos el único control de integridad que se realiza automáticamente es el control de duplicados. El control de integridad referencial queda a cargo del programador, lo que no ocurre en las transacciones (ergo, en un Business Component).

Queda claro de la enumeración mostrada arriba que los Business Components ofrecen todas las garantías y constituirán la forma de actualización privilegiada.

Cabe preguntarse entonces: ¿cuándo actualizar utilizando estos comandos? La respuesta es: cuando la performance sea un problema.

Un ejemplo discutible es el que utilizamos para cambiar el valor del atributo InvoicePendingFlag a False. No había ninguna regla que lo implicara, no involucraba integridad referencial, ni duplicados y podía involucrar millones de registros. ¿Cuál hubiese sido la alternativa? Prender la propiedad Business Component de la transacción Invoice, y en el procedimiento MarkInvoiceAsNotPending definir variable &invoice con ese tipo de datos y luego:

for eachwhere InvoiceDate >= &startDatewhere InvoiceDate <= &endDatewhere InvoicePendingFlag

&invoice.Load ( InvoiceId )&invoice.InvoicePendingFlag = False&invoice.Save()

endfor

Pero esta solución será más ineficiente que la actualización directa utilizando “blocking factor”, sabiendo que se deberán actualizar millones de facturas.

Page 306: Aplicaciones Genexus
Page 307: Aplicaciones Genexus

293

Uso de Subtipos

Page 308: Aplicaciones Genexus

294

• Las relaciones entre atributos GeneXus se establecen a través de sus nombres.

• Mediante subtipos se puede establecer que dos atributos que se llaman diferente corresponden al mismo concepto.

• Casos de subtipos:• A. Múltiples referencias• B. Especialización de un nivel (relación 1‐1)• C. Subtipos recursivos

Definición de subtipos

Page 309: Aplicaciones Genexus

295

{CityId *CityName

}

• Atributos conceptualmente iguales que cumplen roles diferentes(ej.: reservas de pasajes).

A. Múltiples referencias

City{ReservationId*CityIdCityId

}

Reservation

{CityId *CityName

}

origendestino

PROBLEMAAtributos con

el mismo nombre

SOLUCION

City{

ReservationId*ReservationCityFromIdReservationCityToId

}

Reservation

Desapareceel problema!

subtipo

subtipo

Realidad a representar/diseñar: En cada reserva hay dos ciudades involucradas, las cuales cumplen roles diferentes. El rol de una de las ciudades es el de ser la “ciudad de partida” (ciudad origen) y el rol de la otra es el de “ciudad de arribo” (ciudad destino).El dominio de ambas ciudades es el mismo, el de la tabla CITY.

La forma de representar que tanto el “origen” como el “destino” son ciudades de la tabla CITY, es diseñando la transacción “Reservation” en la forma mencionada inicialmente en la transparencia. Sin embargo, no es posible que en la estructura de una transacción figure el mismo atributo más de una vez, pues no habría manera de identificarlos.SOLUCIÓN: llamar a las dos ciudades de la reserva con diferentes nombres de atributos. Cualquiera de las siguientes opciones es válida. Elegimos la 3era por mayor claridad.

Opción 1) ReservationCityFromId ciudad origenCityId ciudad destino (mismo nombre que la PK de CITY)

Opción 2) CityId ciudad origen (mismo nombre que la PK de CITY)ReservationCityToId ciudad destino

Opción 3) ReservationCityFromId ciudad origenReservationCityToId ciudad destino

El problema es que al poner por ejemplo ReservationCityFromId en lugar de CityId, GeneXus deja de inferir que ReservationCityFromId corresponde al código de una ciudad de la tabla de CITY. ¿Cómo hacemos para relacionarlos, siendo que tienen diferente nombre de atributo? ver respuesta en próxima hoja …

Page 310: Aplicaciones Genexus

296

Para estos casos GeneXus provee los SUBTIPOS, que permiten definir que dos atributos que se llaman diferente corresponden al mismo concepto.

En nuestro ejemplo, si definimos al atributo ReservationCityFromId como subtipo de CityId, estamos especificando que si bien ReservationCityFromId y CityId son diferentes atributos (de nombres diferentes), corresponden, no obstante, al mismo concepto (una ciudad de la tabla CITY).

Al establecer que un atributo es subtipo de otro, estamos estableciendo una dependencia funcional entre ellos.

Si ReservationCityFromId es subtipo de CityId, entonces decimos que CityId es el supertipode ReservationCityFromId.

Los atributos que se encuentran en una relación subtipo-supertipo comparten la misma definición (tipo de datos).

Se realizan los controles de integridad referencial automáticamente.

La tabla extendida que se obtiene con la definición del subtipo, es la misma que se obtendría si se utilizara directamente el supertipo.

Page 311: Aplicaciones Genexus

297

• Con la definición de los subtipos antes mencionados:• Se establecen las siguientes relaciones:

• Se  hacen  además  automáticamente  los  controles  de  Integridad Referencial  (IR)  entre  ambas  tablas  cuando  se  utilizan  sus correspondientes transacciones.

• Los atributos secundarios de CITY:Pertenecen  a  la  tabla  extendida  de  RESERVATION,  pero  al  existir  doble referencia  no  se  pueden  utilizar  directamente  desde  RESERVATION (ambigüedad de caminos y con valores de ciudades diferentes). 

Solución definir también subtipos para los atributos secundarios de CITY, e incluirlos en c/u de los grupos de subtipos.

RESERVATION CITYReservationCityFromId

ReservationCityToId

A. Múltiples referencias

IMPORTANTE:Notar que este caso de múltiples referencias puede darse tanto:

• en la tabla base (*)• como en la tabla extendida

(*) es el caso del ejemplo, en el que en la propia tabla (RESERVATION) hay más de una referencia a otra tabla (CITY) y con valores diferentes.

RESUMIENDO:siempre que desde una tabla se accede a otra que está en su tabla extendida por “más de un camino” y con “valores diferentes”, es necesario definir SUBTIPOS, para poder llamarle diferente a los atributos y haciéndose automáticamente todos los controles de integridad referencial. Una vez definidos los grupos de subtipos que sean necesarios, la forma de indicarle a GeneXus cuál de los caminos debe tomar para acceder a la tabla destino, es mencionando los nombres de atributos que correspondan. Ej.: mencionar ReservationCityFromName si lo que se necesita en ese momento es el nombre de la ciudad origen, o mencionar ReservationCityToName si lo que se necesita es el nombre de la ciudad destino.

Page 312: Aplicaciones Genexus

298

A. Múltiples referencias

{ReservationId*ReservationCityFromIdReservationCityFromNameReservationCityToIdReservationCityToName

}

Transacción “Reservation” Tabla “Reservation”{

ReservationId*ReservationCityFromIdReservationCityToId

}FKFK

Nombre de cada grupo de subtipos.

Inferido

Inferido

Con el grupo estamos indicando que los atributos pertenecientes al mismo grupo de subtipos, están relacionados. Por ej., en nuestro ejemplo, GeneXus sabrá que el atributo ReservationCityToName será inferido a través del atributo ReservationCityToId (y no a través del ReservationCityFromId). Esto es por pertenecer ambos al mismo grupo (al de nombre ReservationCityTo). Cuando el usuario digite un valor sobre ReservationCityToId, no solo se va a hacer automáticamente el control de integridad referencial (que exista un ciudad con ese código en la tabla CITY), sino que se va a inferir en ReservationCityToName el nombre correspondiente a ese código de ciudad.

IMPORTANTE: Todo grupo de subtipos, debe contener un atributo o conjunto de atributos, cuyos supertipos, juntos, correspondan a la clave primaria de una tabla del modelo. Los demás atributos del grupo deberán ser de tipo “Inferred”, es decir, deberán poder inferirse a través de esa clave.En caso contrario estará mal definido el grupo.

Page 313: Aplicaciones Genexus

299

SALE COUNTRY

CUSTOMER

SELLER

Un camino desde SALE a COUNTRY: a través del País del cliente (CountryId)

Otro camino desde SALE a COUNTRY: a través del País del vendedor (CountryId)

• COUNTRY pertenece a la tabla extendida de SALE por caminos diferentes y con códigos de país diferentes.

¿qué país imprime? ¿cuál de los caminos toma?Hay una ambigüedad en el modelo de datos!

Layout:

A. Múltiples referencias a la tabla extendida

Source:

Si quisiéramos por ejemplo listar las ventas (SALE), y de c/u de ellas mostrar los datos del cliente (nombre, país, etc.) y del vendedor (nombre, país, etc.):

• necesitamos un for each con tabla base SALE y acceder a través de su extendida a las tablas CUSTOMER, SELLER y COUNTRY para listar los atributos secundarios del cliente, vendedor y país respectivamente.

Problema:Los atributos de nombre CountryId, CountryName y todos los de la tabla extendida de COUNTRY pertenecen a la tabla extendida de SALE por dos caminos diferentes: 1) a través del país del cliente y 2) a través del país del vendedor.

Solución:Debemos diferenciarlos, llamarlos con diferente nombre de atributo pero queriendo que se sigan representando todas las relaciones y haciéndose automáticamente todos los controles de integridad referencial.

Page 314: Aplicaciones Genexus

300

SALE COUNTRY

CUSTOMER

SELLER

Cuando queremos el país del cliente de la venta: SaleCustomerCountryName

Cuando queremos el país del vendedor de la venta: SaleSellerCustomerName

SaleCustomerId

SaleSellerId

A. Múltiples referencias a la tabla extendida

Solución

Una vez definidos los dos grupos de subtipos que se muestran en la figura, y haciendo el cambio correspondiente en la estructura de la transacción Sale, ¡queda resuelta la ambigüedad en el modelo de datos!

Page 315: Aplicaciones Genexus

301

SaleCustomerCountryId SaleSellerCountryId

¡Problema resuelto!

A. Múltiples referencias a la tabla extendida: Solución

Una vez definidos los subtipos, tenemos que recordar usar el nombre de atributo que corresponda a lo que queremos acceder. Por ejemplo, en todos aquellos objetos GeneXus en los cuales queramos acceder al código o al nombre del país del cliente de la venta debemos usar los atributos SaleCustomerCountryId y SaleCustomerCountryName respectivamente.

Page 316: Aplicaciones Genexus

302

B. Especialización de atributos

PERSON

TEACHER STUDENT

Ej.: Sistema para una Universidad …

Sistema Teachers

datos comunes a profesoresy estudiantes

datos propios de los estudiantes

datos propios de los profesores

Sistema Students

Caso de subtipos “Especialización de atributos”:Cuando se está modelando una categorización. Generalmente es utilizada cuando un objeto del negocio comparte todas las características de otro objeto, pero agrega algunas más. La diferencia puede estar tanto en las propiedades, como en el comportamiento que tendrá.

Ejemplo “Sistema para una Universidad”:

En este ejemplo, el profesor y el alumno tienen roles y comportamientos claramente diferenciados. Por ejemplo, el profesor tendrá cursos asignados, sueldo, etc. El alumno estaráinscripto a un curso, tendrá asignados pagos, asistencia, escolaridad, etc.

Estamos frente a un caso en el que los roles y el tratamiento de las entidades de la categorización están claramente diferenciados.

Tanto los estudiantes como los docentes comparten información común (ambos tienen un nombre, una dirección, etc) pero también tienen información que difiere, que es propia de c/u de ellos.

Para representar esta realidad, se crean las tres transacciones: “Person”, “Teacher” y “Student”.

En la transacción “Person” figura la información común. Para representar que tanto los estudiantes como los docentes son personas, se utilizan los subtipos.

Al definir que el identificador de “Teacher” es subtipo del identificador de “Person” estamos estableciendo esta relación.

Cada vez que se inserte un registro en la tabla TEACHER a través de su transacción, se realizará el chequeo de integridad referencial contra “Person”. Asimismo, cada vez que se intente eliminar un registro de “Person”, se verificará primeramente que no exista ningún registro en la tabla TEACHER (ni en STUDENT) con el mismo valor en la clave primaria.

Page 317: Aplicaciones Genexus

303

B. Especialización de atributos

“Person” “Teacher” “Student”{

PersonId*PersonNamePersonAddress

}

{TeacherId*TeacherNameTeacherAddressTeacherSalary

}

{StudentId*StudentNameStudentAddressStudentAverage

}

• Se crean 3 tablas físicas.• Se realizan chequeos de IR contra la tabla PERSON.

La transacción “Teacher” tiene asociada una tabla que contendrá físicamente sólo dos atributos: TeacherId y TeacherSalary.

Al ser TeacherId identificador de la transacción, será la clave primaria de la tabla asociada. Además, al ser un subtipo de PersonId, será una clave foránea a la tabla PERSON. Por lo tanto, se harán los chequeos de integridad referencial correspondientes.

Los atributos TeacherName y TeacherAddress son subtipos de PersonName y de PersonAddress respectivamente y están agrupados con TeacherId, por lo que serán inferidos de la tabla PERSON, a través de la clave foránea TeacherId (no están almacenados en la tabla TEACHER).

Page 318: Aplicaciones Genexus

304

• Ejemplo: Employee‐Manager

Error(‘Debe ingresar un gerente para el empleado’) if not EmployeeIsManagerFlag andEmployeeManagerId.isnull();

Tabla EMPLOYEE

{EmployeeId*EmployeeNameEmployeeIsManagerFlagEmployeeManagerId

} FK

C. Subtipos recursivos

Es posible tener una tabla subordinada a sí misma definiendo subtipos.

Este tipo de subtipos se utiliza para modelar las relaciones recursivas. Por ejemplo, la relación entre Empleado y Gerente: - cada empleado tiene un gerente. Un gerente, a su vez, es un empleado (aquí está la recursión).- un gerente puede tener varios empleados a su cargo.

Si además la realidad a representar es que “sólo los empleados que no son gerentes tienen un gerente”, entonces, cuando se ingresan los datos hay que realizar los siguientes controles:- cuando se ingresan los gerentes, hay que permitir dejar en nulo el atributo EmployeeManagerId. Para esto, cambiamos a ‘Yes’ la columna Nulls del atributo EmployeeManagerId, el cual es FK en la tabla EMPLOYEE.- que todo empleado que no es gerente, tenga un gerente. Este control lo hacemos con la regla error que se muestra en la figura.

El atributo EmployeeManagerName no queda almacenado en la tabla EMPLOYEE, se infiere luego de ingresar un valor en EmployeeManagerId.

Por ser EmployeeManagerId subtipo de EmployeeId, se realizan automáticamente los controles de integridad referencial de la tabla consigo misma. Esto se puede ver en la navegación de la transacción, como se muestra en la siguiente página.

Page 319: Aplicaciones Genexus

305

• Listado de navegación detallado:

C. Subtipos recursivos

Page 320: Aplicaciones Genexus

306

• Cuando se define un subtipo éste "hereda"  la definición del supertipo.

• Al menos  uno  de  los  supertipos  del  grupo  (o  conjunto  de supertipos del grupo) debe(n)  corresponder a  la PK de una tabla del modelo. 

Consideraciones

Page 321: Aplicaciones Genexus
Page 322: Aplicaciones Genexus

307

Patterns

Page 323: Aplicaciones Genexus

308

Patterns: Escenario

Filtro sobre losdatos

Paginación

Teniendo la transacción Country y la transacción Customer, queremos lograr hacer la aplicación más vistosa, con consultas con vistas más completas y con algún aumento de funcionalidad.

Por ejemplo, trabajar con los países de una forma más vistosa y amigable que la que brinda la sola transacción. Visualizar en un grid los países existentes, con la posibilidad de filtrar por nombre de país, y fijando paginado al grid, de forma tal que muestre un número fijo de registros por página...

Page 324: Aplicaciones Genexus

309

Patterns: Escenario

New Country

Update Country

Delete Country

Transaction

...así como poder ingresar un nuevo país (mediante la transacción Country), o seleccionar uno de los mostrados en el grid, para poder modificarlo o eliminarlo...

Page 325: Aplicaciones Genexus

310

Patterns: Escenario

...o incluso ver la información completa de ese país, incluyendo los clientes asociados...

Page 326: Aplicaciones Genexus

311

Definición Patrones que se pueden aplicar a una KB paraimplementar automáticamente cierta funcionalidad.

Patterns

Patrones disponibles:

• Work With• Category

Selectores dentro de las Transacciones

Generalidades

• Una vez aplicado el patrón, todos los objetos generados quedan como parte de la Base de Conocimiento.

Es natural al desarrollar aplicaciones, tener que resolver partes muy similares pero no exactamente iguales.

Por ejemplo, si en una Base de Conocimiento se tienen modelados los objetos de la realidad Customersy Countries, a pesar de ser dichos objetos bien diferentes, los “Work With Customers” y “Work WithCountries” respectivamente, tienen muchas cosas en común: un grid en el form, un conjunto de variables para utilizar en filtros, opciones de ordenamiento de la consulta, invocaciones a la transacción correspondiente para actualizar la base de datos, etc..

Surgen entonces los Patterns, que ofrecen la posibilidad de aplicar un patrón (pattern) a las instancias que se deseen de una Base de Conocimiento, y generar todos los objetos GeneXus necesarios para implementar cierta funcionalidad, teniendo en cuenta sus datos específicos.

Siguiendo con el ejemplo mencionado inicialmente, es posible aplicar el patrón “Work With” a la Base de Conocimiento, de forma tal que partiendo de las transacciones “Customer” y “Country”, se obtenga todo el desarrollo correspondiente al “Work With Customers” y “Work With Countries” para ambiente web(pantallas vistosas que implementan las consultas, con ordenamientos, filtros, invocaciones a las transacciones correspondientes, y más).

Page 327: Aplicaciones Genexus

312

PatternsWork With

Transacción

View

Genera a partir de una Transacción:

• Pantalla Work With: consulta interactiva, múltiples ordenamientos,filtros, invocación a la transacción, etc.

Work With

• Pantalla View: Registro seleccionado, con la información asociada.

La pantalla Work With ofrece:• Consulta interactiva• Múltiples ordenamientos• Filtros• Invocación a la Transacción en los diferentes modos (insert, update, delete, display)• Posibilidad de incluir invocadores propios a objetos• Link en cada línea de la grilla a la pantalla ‘View’

La pantalla View muestra:• La información del registro seleccionado en la grilla Work With• Un tab control con:

• Un tab con la información del registro• Un tab por cada tabla subordinada a la tabla base del registro en la grilla Work With.:

Page 328: Aplicaciones Genexus

313

PatternsAplicación

• Abrir la Transacción.

• Seleccionar el patrón a aplicar (aparecerá la instancia por defecto).

• Marcar la opción “Apply thispattern on save”.

• Grabar la Transacción.

Para aplicar el pattern sin demoras, alcanzará con editar la instancia (selector “Work With” de la transacción), marcar el check box y grabar. ¡Listo! Con eso se crearán automáticamente los objetos GeneXus que implementan el pattern (en particular la pantalla de selección y filtro y la pantalla de Viewque mostramos antes). Asimismo se modificará la transacción para que ahora reciba por parámetro el modo (Insert, Update, Delete, Display) y el país.

Page 329: Aplicaciones Genexus

314

PatternsWork With: objetos generados

Consecuencia: Se generan en la KB los objetos que ya vimos en ejecución. ¿Dónde? En el Folder View, bajo la propia transacción:

Una vez grabada la instancia, en el folder view, bajo el nombre de la transacción, aparecerá el nombre del pattern aplicado a la misma (en nuestro ejemplo WorkWithCountry) y todos los objetos que GeneXusdebe crear para implementarlo.

En nuestro caso se crearán 2 objetos de tipo Web Component, y 2 objetos de tipo Web Panel. Son muy similiares. La diferencia es que un Web Component puede incluirse dentro de otro objeto. No entraremos en detalles en este momento.

Page 330: Aplicaciones Genexus

315

PatternsEjemplo

Aplicación del pattern Work With a la transacción Country.

N

1

Al aplicar el pattern Work With a la transacción Country, se creará:• Pantalla Work With:

• Tendrá una grilla con los atributos de la transacción: CountryId y CountryName. • Se podrá ordenar y filtrar por CountryName, por ser CountryName el atributo descriptor.• Se podrá invocar a la transacción en los diferentes modos (Insert, Update, Delete).

• Pantalla View: Mostrará dos tabs. El primer tab tendrá la información del país seleccionado, y el segundo tendrá la información de los clientes pertenecientes a dicho país (puesto que existe unarelación 1-N entre las tablas Country y Customer asociadas a las transacciones de igual nombre).

Page 331: Aplicaciones Genexus

316

PatternsComenzando a asociar... pantalla Work With

Se sitúa en el paísindicado, o muestratodos los países.

Son muchas las propiedades que se ofrecen en las instancias correspondientes al patrón Work With, para personalizar el comportamiento de los objetos que se generarán. A continuación describimos algunas de ellas.

El nodo Selection ofrece las propiedades relacionadas a la pantalla Work With que se generará para la instancia. Sus sub-nodos son:

Modes (Ins, Upd, Del, Dis)Este nodo permite definir en cuáles modos se ofrecerá invocar a la transacción. Las posibilidades y sus valores por defecto son:

Insert: TrueUpdate: TrueDelete: TrueDisplay: False

En la instancia aparece <default> al lado de cada una de las propiedades anteriores. ¿Dónde se configura este valor por defecto? Lo veremos unas páginas más adelante.

Para cada modo podrá especificarse una condición. Se proveen las siguientes propiedades para ese propósito: Insert Condition, Update Condition, Delete Condition, Display Condition.

Si se define una condición asociada a un modo, la invocación para ese modo solo se habilitará si la evaluación de la condición es verdadera (Ejemplo: CountryId=10).

Page 332: Aplicaciones Genexus

317

PatternsPersonalización... pantalla Work With

• Agregar, eliminar, ocultar atributos o variables del grid.

• Especificar los modos de invocación a la transacción.

• Definir órdenes y filtros.

• Agregar, eliminar, modificar Acciones.

Posicionarse en el nodo correspondientey presionar el botón derecho del mouse.

Attributes

Este nodo permite definir cuáles atributos se desean mostrar en el grid (y para cada atributo, se pueden personalizar sus propiedades). Por defecto muestra todos los atributos de la estructura de la transacción.

Orders

Es posible ofrecer al usuario final varios órdenes posibles para ver el resultado de la consulta (es decir, las líneas mostrando los datos en el grid). Utilizando el botón derecho del mouse se puede definir un nuevo orden (su nombre y composición). Cada orden puede estar compuesto por varios atributos (pudiendo indicar para cada uno de ellos si se desea orden ascendente o descendente). Se presentaráun combobox en la pantalla Work With ofreciendo todos los órdenes posibles de seleccionar, para que el usuario final elija uno y los datos se presenten en el grid ordenados por el mismo. Sin embargo, el control grid ya presenta la posibilidad de ordenar en ejecución, simplemente cliqueando sobre la columna por la que se desean tener ordenados los datos. Pero hay que tener en cuenta que esa funcionalidad solo permite ordenar en ejecución los datos de la página del grid que se está mostrando.

Filter

Este nodo permite definir condiciones de filtro, para que en el grid se muestren solo los registros que cumplan con las mismas.

Actions

El nodo Actions permite incorporar acciones propias a la pantalla Work With. Es decir, permite agregar botones (dentro o fuera del grid) que invoquen a los objetos que se indiquen, con sus correspondientes parámetros. Si bien el nodo Actions no está visible por defecto, estando posicionado en el nodo Selection y presionando el botón derecho del mouse, se ofrecerá la opción Add Actions que lo agregará. Una vez agregado este nodo, estando posicionado sobre el mismo y presionando el botón derecho del mouse, se ofrecerá la opción Add Action que permitirá agregar una acción con su nombre de acción, caption, objeto invocado, etc.

Page 333: Aplicaciones Genexus

318

PatternsPersonalización - Ejemplos

1) Ocultar atributo CountryId del grid.

F4

¿Por qué ocultarlo en lugar de eliminarlo?

El atributo CountryId, a diferencia del CountryName, no puede ser eliminado del grid, debido a que es el atributo que se envía a la transacción ‘Country’ cuando el usuario desea modificar o eliminar el país mostrado en una línea del grid del Work With.

Page 334: Aplicaciones Genexus

319

PatternsPersonalización - Ejemplos

2) Eliminar modo Delete desde el grid.

F4

Al editar las propiedades estando posicionados en el nodo de la instancia que se muestra, podemos observar que cada uno de los modos en que se puede invocar una transacción (para insertar, modificar, eliminar o incluso deplegar) están listados como propiedades. Podemos ver también que aparece una propiedad Export que permite exportar los datos a una planilla excel.

Otra vez aquí podemos apreciar que cada una de las propiedades tiene el valor <default> que aún no sabemos de dónde es tomado. Pero si queremos fijar un valor independiente de cuál sea el default, podemos editar el combo box que presentará tres valores: <default>, ‘true’, o ‘false’.

Hemos fijado el valor de la propiedad Delete en ‘false’. Podemos ver en ejecución la repercusión. Ya no aparece en el grid la primera columna que contenía la imagen que permitía eliminar el país. Ahora no se podrá desde esta pantalla eliminar países.

Obsérvese también cómo ha desaparecido del grid el atributo CountryId. Lo habíamos ocultado en la página anterior.

Page 335: Aplicaciones Genexus

320

PatternsPersonalización - Ejemplos

3) Agregar una Acción a la pantalla Work With Countries que

invoque al proceso de facturación: BillingProcess.

a) Clic con el botón derecho

sobre el nodo Selection

b) Clic con botón derecho sobreel nodo Actions que aparecióal final.

Page 336: Aplicaciones Genexus

321

PatternsPersonalización - Ejemplos

c) Definir la Acción editando sus

propiedades (F4).

Botón fuera del grid.

Nombre de la acción y objeto que se invoca.

d) Finalmente en ejecución, se

observa el botón fuera del grid.

Ya habíamos definido el objeto BillingProcess para realizar la facturación del mes a todos los clientes. Aquí estamos agregando un botón fuera del grid, que al presionarlo llama a este otro objeto GeneXusque habíamos creado antes.

Page 337: Aplicaciones Genexus

322

PatternsAsociando... pantalla View

El nodo View por su parte, ofrece las propiedades relacionadas a la pantalla View que se generará para la instancia. Muestra toda la información de un registro, que fue seleccionado en el grid del Work With(la información del registro es mostrada en una solapa de un tab control, y además hay una solapa con un grid por cada tabla directamente subordinada, para mostrar la información relacionada).

Page 338: Aplicaciones Genexus

323

PatternsPersonalización - Ejemplos

1) Quitar atributos CustomerGender y CustomerStatus del tab Customer de la pantalla View Country.

a) Posicionarse sobre el atributoy borrarlo con la tecla de eliminación del teclado o botón derecho/Delete.

En este caso si no queremos que los atributos CustomerGender y CustomerStatus se vean en el grid en ejecución, no necesitamos ocultarlos. Podemos directamente eliminarlos.

Page 339: Aplicaciones Genexus

324

PatternsPersonalización - Ejemplos

2) Agregar un filtro por CustomerName en el tab Customer.

a) Click con el botón derecho

sobre el tab Customer

b) Indicar el atributo sobre el cual filtrar,

editando las propiedades (F4).

Una vez que ejecuta el paso a) y elige ‘Filter’ aparecerá un nuevo nodo Filter inmediatamente después del nodo Attributes, con 2 subnodos: Attributes y Conditions.

Luego, en el paso b), deberá posicionarse en el subnodo Attributes y hacer botón derecho, donde se le ofrecerá la posibilidad de agregar un atributo de filtro. Al editar las propiedades, usted deberá presionar el combo box que le desplegará una ventana donde ingresará el atributo (en nuestro caso, CustomerName). Con esto se creará automáticamente una variable de igual nombre que el atributo &CustomerName, que será el control que aparecerá en ejecución para que el usuario digite allí el filtro. Veamos el paso siguiente...

Page 340: Aplicaciones Genexus

325

PatternsPersonalización - Ejemplos

(Continuación)

c) Definir la condición correspondiente.

Page 341: Aplicaciones Genexus

326

PatternsValores por defecto para las propiedades

Propiedades (F4)

El patrón Work With además de generar objetos nuevos, también modifica las transacciones, para que sean invocadas por los objetos generados por el pattern, agregándoles regla parm, etc.Relacionado a esto, cada instancia contiene la propiedad UpdateTransaction, que ofrece los siguientes valores:

Do not update: La transacción no será modificada (web form, reglas y eventos serán mantenidos).Only rules and events: Solo las reglas y eventos se modificarán, no se modifica el web form. Apply WW Style: La primera vez que se aplique el patrón, el comportamiento será el mismo que si se hubiese seleccionado el valor Create Default. A partir de la segunda vez que se aplique el patrón, no se modificará la data area del form de la transacción (por si se personalizó y se desea mantener), y sí se modificará el style area, así como los eventos y reglas. Create default: Reglas, eventos y form de la transacción (tanto data area como style area) serán modificados. En lo que respecta al form, será como seleccionar la opción Apply default (Web Form).

El valor por defecto para esta propiedad es Only rules and events.

En cuanto a las propiedades AfterInsert, AfterUpdate y AfterDelete, permiten definir el comportamiento luego de que se inserta, modifica o elimina un registro.

Los valores posibles para cada una de ellas son:• <default>• Return to caller• Go to View• Go to Selection

Otra vez el valor <default>. Llegó el momento de ver dónde se configuran todos estos valores pordefecto que hemos ido encontrando en la instancia...

Page 342: Aplicaciones Genexus

327

PatternsPattern Settings

• Configuración de propiedades generales (para todas las instancias).

En este lugar están centralizados los <default> para toda instancia. Podemos ver que en el nodo Template se ofrecen algunas de las propiedades que mencionamos en la página anterior.

El tamaño de página de los grids del work with, que en las imágenes anteriores era de 3 (se mostraban 3 líneas por página del grid) se configura en el nodo Grid. El valor por defecto de esta propiedad es Page.Rows. Es decir, el valor del dominio enumerado Pages creado por GeneXus automáticamente al aplicar el pattern por primera vez. El valor que tiene Page es 10. Nosotros lo habíamos cambiado a 3 para que nos entraran las imágenes completas en estas slides.

Page 343: Aplicaciones Genexus

328

• Todos los objetos generados por Patterns están basados en el esquema de Defaults de GeneXus. Cada parte de un objeto es generada como Default..

• La implementación basada en Defaults permite tener dinamismo entre la Transacción y el patrón.

• El dinamismo se mantiene para todas las partes default del objeto• Opción Edit / Apply Default del Menú para volver al default de una parte o de 

todas las partes (All parts)

• Ejemplo: si agregamos atributo CountryFlag a la estructura de Country, ¿quépasará con el grid del Work With Countries? Si éste conserva el Defaul, seráagregada automáticamente columna CountryFlag al grid.

No es necesario reaplicar el patrón, los cambios se ven al abrir nuevamente el objeto

PatternsDinamismo entre la Transacción y Patterns

El dinamismo mencionado se mantiene para todas las partes default de los objetos.

Todos los objetos generados por Patterns están basados en el esquema de Defaults de GeneXus. Cada parte (Form, Reglas, Eventos) de cada objeto es generado como Default. Si se modifica alguna parte del objeto, ésta deja de ser Default.

Por ejemplo, si se modifica el web form de un WW (no queda como default), y se agrega un nuevo atributo a la transacción, no se va a actualizar automáticamente el grid del WW con ese atributo (o sea, no se agregará dicho atributo).

La implementación basada en Defaults permite tener dinamismo entre la Transacción y el patrón

• Cambiar propiedades en la definición del patrón (Pattern setting)• Cambios en la instancia (agregar un nuevo filtro)• Cambios en la Transacción (agregar un nuevo atributo)

Si se quiere volver al dinamismo, se deberá tener nuevamente las partes como default.Para esto, se debe seleccionar desde el Menú Edit / Apply Default (la parte donde se tiene abierto el objeto) o Apply Default (All parts), lo cual vuelve a default todas las partes que se habían modificado.

Page 344: Aplicaciones Genexus

329

PatternsCómo borrar los objetos generados por Patterns

• Seleccionar la instancia en el Folder View, presionar botón derecho / opción “Delete” o presionar la tecla DEL. Aparecerá el mensaje:

• Al confirmar el mensaje:

• Se borrarán todos los objetos generados por Patterns asociados a la Transacción.

• Se borrarán todos las reglas y eventos agregados por Patterns en la Transacción.

• Se desmarcará la opción “Apply this pattern on save” de la Transacción.

Page 345: Aplicaciones Genexus
Page 346: Aplicaciones Genexus

330

Objeto Web Panel

Page 347: Aplicaciones Genexus

331

Definición Objetos GeneXus que permiten al usuario realizar consultas interactivas a la base de datos a través de una pantalla en tiempo de ejecución.

Web PanelsGeneralidades

• Son flexibles, por lo que se prestan para múltiples usos.

• Algunos web panels conocidos:

• Work With Countries.

• View Country.

• Elementos que los componen:

Los elementos de los web panels son:

Web Form: Cada web panel contiene un form Web, el cual debe ser diseñado por el analista agregándole variables, atributos, así como otros controles, para que el usuario pueda interactuar con el mismo.

Rules: Las reglas de un web panel permiten definir ciertos comportamientos puntuales de dicho objeto. Por ejemplo, declarar qué parámetros recibe.

Events: Los web panels emplean la programación orientada a eventos. Este tipo de programación permite definir código ocioso, que se activa en respuesta a ciertas acciones provocadas por el usuario o por el sistema. En esta sección de un web panel es donde se define el código ocioso asociado a los eventos que pueden ocurrir durante la ejecución del web panel. Aquí también pueden programarse subrutinas a ser invocadas por varios eventos.

Conditions: Es para definir las condiciones (globales) que deben cumplir los datos a ser recuperados (filtros). Análogo a la solapa de igual nombre del objeto Procedure.

Variables: aquí se declaran las variables que serán utilizadas dentro del objeto. Recordar que son locales.

Help: Permite la inclusión de texto de ayuda, que los usuarios podrán consultar en tiempo de ejecución del web panel.

Documentation: Permite la inclusión de texto técnico en formato tipo wiki, como documentación para el equipo involucrado en el desarrollo de la aplicación.

Propiedades: Son características a ser configuradas para definir ciertos detalles referentes al comportamiento general del web panel. Recordar que se acceden con F4.

Page 348: Aplicaciones Genexus

332

Web PanelsPara el ingreso de datos

Event Enter

1

En el ejemplo, el web panel contiene dos variables &startDate y &endDate como se muestra arriba. En tiempo de ejecución, el usuario podrá ingresar valores en las variables dado que en los web panels las variables son por defecto de entrada (salvo las incluidas en grids, como veremos).

En el evento Enter del web panel (asociado al botón Billing Generation), se obtienen para cada cliente las facturas cuyas fechas se encuentren en el rango especificado y se genera recibo para el cliente (invocando al Data Provider que devuelve la colección de Business Components que ya hemos visto oportunamente cuando estudiamos esos temas).

De modo que este web panel tiene como finalidad permitir al usuario ingresar un rango de fechas, y presionando el botón Billing Generation, ejecutar el procesamiento de las facturas.

Page 349: Aplicaciones Genexus

333

Web PanelsPara exhibir datos de un registro

parm(in: CustomerId );

Tabla base: CUSTOMER

Customer

{

CustomerId*

CustomerName

CountryId

CountryName

CustomerAddress

CustomerGender

CustomerStatus

CustomerPhoto

}

Se muestran los datos del cliente

blob

2

El web panel mostrado arriba ha sido creado para exhibir los datos de un cliente. Se necesita invocarlo desde otro objeto (como ya veremos), pasándole por parámetro el código del cliente del cual se quiere mostrar la información.

Un web panel es un objeto típicamente utilizado para mostrar información. Entonces, cuando GeneXus encuentra atributos en el form, ¿qué intención adjudicará al programador que los puso allí? Pues, que le está pidiendo implícitamente que vaya a buscar los datos correspondientes a la base de datos para desplegarlos.

En definitiva, con el web panel anterior, GeneXus irá a la tabla CUSTOMER y filtrando por el atributo recibido por parámetro, CustomerId, mostrará la información del registro encontrado. ¿Qué información? La que reside en los atributos que figuran en el form. Pero el atributo CountryName no se encuentra en la tabla CUSTOMER. Pues sucede lo mismo que con un for each, un grupo de Data Providers, etc., es decir, desde el registro de la tabla base, se accede al registro relacionado de la tabla extendida que se necesite, para obtener el valor del atributo requerido (en nuestro caso accede a la tabla COUNTRY para recuperar el valor de CountryName).

Las inferencias que GeneXus realiza son las siguientes:

Al tratarse de un web panel, los atributos que figuren serán de consulta1. Entonces GeneXus deberá acceder a la base de datos para recuperar sus valores. ¿A qué tablas? Dependerá de si el Web panel tiene grids o no:

• Web panel plano (sin grid): están los atributos “sueltos” en el form, como en el caso que estamos mostrando. Si esto sucede, es porque el analista necesita acceder a información de un registro de una tabla (y eventualmente de los registros relacionados por tabla extendida), como es el caso del ejemplo. En este caso, el web panel estará bien programado si además se agrega un filtro que determine “ese” registro a mostrar. En nuestro caso, tenemos la regla parm que al recibir en atributo PK de la tabla sólo recuperará un registro. En definitiva, GeneXus determina una tabla base del web panel, así como lo hacía para un for each. ¿Cómo? Buscando la mínima tabla extendida que contenga a los atributos...

• Web panel con uno o más grids: lo veremos en lo que sigue, pero ya podemos intuirlo... ¿qué sentido tendrácolocar un grid? Mostrar información repetitiva. En el caso general: cada grid mostrará muchos registros de una tabla (y su información asociada).

--------------------------------------------------------------------------------------------------------------------1 Al contrario de lo que sucede con los atributos en las transacciones (salvo los inferidos o los que tienen regla noaccept o propiedad Enabled deshabilitada).

Page 350: Aplicaciones Genexus

334

Web PanelsPara exhibir múltiples registros: Grid (con tabla base)...

Grid: Carga líneas de información en un archivo temporal.

CUSTOMER COUNTRY Tabla base: CUSTOMER

Ejemplo: Mostrar todos los clientes

3

Este web panel, a diferencia del anterior no es plano.Cuando se incluye un grid en un form, se está indicando que se va a mostrar una cantidad indefinida de datos (en este caso, clientes).

Dado que en este web panel hay involucrados atributos, GeneXus infiere que se desea acceder a la base de datos. Simplemente diciéndole qué atributos se desean desplegar, sin necesidad de más información, ya sabrá qué hacer. Existe un grid, hay atributos, entonces, necesariamente habrá tabla base, esto es, la tabla de la base de datos que se navegará en busca de la información requerida.Si en lugar de mostrar esta información en pantalla, la quisiéramos en un listado, crearíamos un procedimiento con un print block ‘customer’ con los atributos CustomerName y CountryName y en el source programaríamos:

for eachprint customer

endfor

Esto es análogo, solo que el for each está implícito, no hay que especificarlo. Cada línea del grid que se carga, es como el print que se ejecuta en cada iteración del for each del listado.

De las tablas CUSTOMER y COUNTRY y de la relación entre ambas es Na1, GeneXus determina la tabla base de este web panel (aquella tal que su tabla extendida sea la mínima que cumple que contiene a todos los atributos referidos). Obsérvese que este ejemplo solo difiere del anterior, en que los atributos aparecen en un grid, y por tanto, no habrá que filtrar quedándose con un solo registro de CUSTOMER. En este web panel no hay regla parm que establezca filtro alguno. También conseguiremos más adelante que este web panel no solamente se remita a mostrar los clientes de la base de datos en el grid, sino que además permita filtrar los clientes que se deseen ver en cada oportunidad, ya sea por nombre de cliente, por país del cliente, o por ambos. Por eso las variables que aparecen en el form.

Page 351: Aplicaciones Genexus

335

Web Panels... Load automático

CustomerId CustomerName CountryId .

1 Susan Jones 2 .

2 Richard Smith 2 .

3 Martina Rodríguez 1 .

4 Hugo Romero 4 .

... ... ... .

Customer table

CountryId CountryName

1 Uruguay

2 United States

3 Italy

4 Venezuela

... ...

Country table

loadloadload

load

For each implícito:para c/customer buscar nombre de país asociado y Load se cargalínea en el grid.

Base de datos

3

Cuando GeneXus puede determinar automáticamente una tabla a recorrer para cargar las líneas del grid, lo hace, y en ese caso no habrá necesidad de brindarle esa información. Es por ello que decimosque en ese caso hay un for each ‘implícito’. Luego veremos casos en los que esto no ocurre (grids sin tabla base).

Obsérvese en el ejemplo, que si en la tabla base existen 4 registros, se cargarán uno a uno los cuatro.

Si ahora queremos que el usuario pueda filtrar los clientes que desea ver... ahí entran en juego lasvariables que hemos definido en la parte fija del form, como veremos en la página siguiente.

Page 352: Aplicaciones Genexus

336

Web Panels

Ejemplo: Mostrar los clientes que cumplen condiciones:

Por defecto de entrada

...filtrando

3

Obsérvese cómo en la ventana de propiedades del control Grid, aparece una de nombre ‘Conditions’. Cliqueando en el combo se abrirá un editor para especificar las condiciones booleanas que deberáncumplir los registros para ser cargados como líneas del grid.

Es por esa razón que se han agregado las variables &CustomerName y &CountryName al form del web panel, de manera tal que el usuario pueda ingresar allí valores que operen como filtros sobre los datos a mostrar. En nuestro caso, hemos establecido filtros con el operador like. Las variables en la parte planadel form de web panels son por defecto de entrada. Luego veremos que en principio si están en grids serán por defecto de salida.

Obsérvese que las condiciones (separadas con “;”) equivalen a las que aparecían en las cláusulaswhere de un for each (o grupo repetitivo de data provider).

De la misma manera, por cuestiones de optimización, puede determinarse, al igual que se hacía en un for each, criterio de ordenamiento de la tabla a recorrerse, como se muestra arriba en el ejemplo.

Nota: Asimismo, igual que en un procedimiento, no sólo pueden establecerse condiciones locales al grid (for each), sino también generales, mediante el selector Conditions. Esto tendrá sentido cuando se tenga más de un grid (for each), para no tener que repetir la misma condición cada vez.

Page 353: Aplicaciones Genexus

337

Web Panels...con refresh automático

DBDB

Refresh

Server

Client

LoadLoad...

Eventos del sistema: Refresh y Load...

3

La propiedad Automatic Refresh que se encuentra a nivel del Web Panel puede tomar los siguientes valores:• When variables in conditions change (valor por defecto): luego de provocarse automáticamente el refresh, se dispara el evento Load cargándose el grid según los nuevos valores de las variables.• No

Dependiendo del tipo de datos del filtro, y del control web utilizado para filtrar, la condición será aplicada cuando se está digitando o al abandonar el campo.En el caso de filtros en controles edit, para tipo de datos Character, son aplicados cuando el usuario los va digitando. Para tipo de datos Date, DateTime y Numeric, las condiciones se evalúan cuando se abandona el campo. En el caso de filtros combo boxes o dynamic combos, las condiciones son evaluadas cuando se abandona el campo. Para Check boxes y Radio buttons, las condiciones son evaluadas cuando el valor es cambiado.

Ejecución: ¿qué sucede en el cliente y en el servidor al tener la propiedad por defecto y un grid con tabla base?

1ª ejecución (variables vacías):For each CUSTOMER

guardar en memoria CustomerNameacceder a registro de COUNTRY relacionado

guardar en memoria CountryNamecargar (load) línea en el grid con ambos valores

N-ésima ejecución (cambia valor de variable de las conditions):Automáticamente en el browser del cliente se detecta cambio refesh en el servidor para volver a cargar el gridcon los registros que cumplan las condiciones (con los nuevos valores de las variables) load por cada línea.

Conclusión: Existen dos eventos del sistema que ocurren en el momento de carga del form (Refresh) y de carga de cada línea del grid (Load). Como veremos, a estos eventos puede asociárseles código para que se ejecute en esosmomentos específicos...

Page 354: Aplicaciones Genexus

338

Web Panels... programando el evento Load

Intención: para aquellos clientes con estado ‘On Hold’ poder activarlos marcando check box y presionando botón ‘Activate’. Antes queremos:

Agregamos al grid atributo CustomerStatus y variable &select booleana...

1. Solo habilitar check box para los ‘On Hold’:Cuando se carga cada línea del grid, si el valor del atributo CustomerStatus de la tabla CUSTOMER a ser cargado es On Hold, habilitar check box...

3

Ampliaremos la funcionalidad de nuestro web panel, permitiendo ver el estado de cada cliente, y para aquellos que estén ‘On Hold’, brindando la posibilidad de pasarlos al estado ‘Active’.

Para hacer esto, agregaremos al grid el atributo CustomerStatus que muestra el estado, y una variable booleana &Select, que permitirá al usuario seleccionar aquellos clientes que desea ‘activar’. Además un botón para efectivamente activar todos los clientes marcados. Pero esto lo haremos en un segundo paso.

Obsérvese que al ser el tipo de datos de la variable &select booleano, por defecto aparece en el gridcomo un check box. Para asegurar que el usuario solamente intente ‘activar’ clientes ‘On Hold’, deseamos que solamente aparezca habilitado este check box cuando corresponde... para ello necesitaremos programar la carga de cada línea, esto es, el evento Load...

Page 355: Aplicaciones Genexus

339

Web Panels... programando el evento Load

Se dispara una vez por cada registro de la tabla base a ser cargado... (tenga código programado o no)

CustomerId CustomerName CustomerStatus ...

1 Susan Jones A ...

2 Richard Smith O ...

3 Martina Rodríguez C ...

4 Hugo Romero A ...

... ... ...

Customer table

3

En la sección Events del web panel, programamos el evento Load del grid que vemos arriba. En el ejemplo, customerGrid es el nombre que hemos dado al control grid en el form.

Al tratarse de un web panel con un único grid, también podríamos haber programado el evento Load a secas:

Event Loadif CustomerStatus = Status.OnHold

&select.Enabled = 1else

&select.Enabled = 0endif

endevent

Es decir, en el caso de un web panel con un único grid, no es necesario calificar el evento con el nombre del grid. Igualmente recomendamos hacerlo, anticipándonos a la posibilidad futura de agregar otro grid al form del web panel.

El evento Load se disparará por cada línea que haya de cargarse en el grid, se encuentre éste programado o no. Lo que hacemos en el ejemplo es aprovechar ese momento inmediatamente anterior a la carga, para efectuar una acción. Y ese es el código que incluimos en el evento.

Ahora sí, estamos en condiciones de implementar la ‘activación’, para lo que necesitaremos asociar al botón un evento, que podrá ser el evento Enter o uno de usuario...

Page 356: Aplicaciones Genexus

340

Web Panels... evento Enter

2. Activar los clientes ‘On Hold’ seleccionados:

For each line in customerGridif &select

&customer.Load( CustomerId )&customer.CustomerStatus = Status.Active&customer.Save()Commit

endifendforComando For each line...

Recorre líneas de un grid&customer BC ‘Customer’

3

En el ejemplo, cuando el usuario presiona el botón ‘Confirm’, necesitamos recorrer todas las líneas del grid, y para cada una de ellas, si el check box de la variable booleana &Select fue marcado por el usuario, entonces debemos cambiar el estado del cliente correspondiente, de ‘On Hold’ a ‘Active’.

Al insertar el botón en el form del web panel, y editar sus propiedades, podrá observarse que pordefecto, el botón está asociado al evento Enter (ver propiedad OnClickEvent).

El Enter será un evento del sistema, que se ejecuta tanto cuando el usuario hace clic sobre el control asociado, como cuando presiona la tecla Enter.

En este ejemplo veremos a la vez:• Posibilidad de definir eventos de usuario y asociárselos a controles o de utilizar el evento Enter del sistema.• Comando For each line, para recorrer las líneas ya cargadas en un grid.• Variables en un grid pasan de ser Read only (de salida) por defecto, a ser de entrada, cuando se utiliza comando for each line en ese grid (también cuando se programan eventos OnClickEvent, Click, etc., sobre alguna columna del grid).

Obsérvese que el comando For each line sólo tiene en común con el comando For each estudiadoantes, el hecho de representar una estructura repetitiva. La diferencia más importante: mientras el for each recorre registros de una tabla (base) de la base de datos, el for each line recorre las líneas de un grid.En nuestro ejemplo hemos definido una variable &customer, Business Component Customer, mediantela cuál cambiaremos a estado ‘Active’ todas las líneas del grid marcadas por el usuario. Para ellorecorremos el grid con el comando for each line.

Page 357: Aplicaciones Genexus

341

Web Panels... o evento de usuario

2. Activar los clientes ‘On Hold’ seleccionados:

For each line in customerGridif &select

&customer.Load( CustomerId )&customer.CustomerStatus = Status.Active&customer.Save()Commit

endifendfor

3

Otra posibilidad, en lugar de utilizar el evento del sistema Enter, es definir un evento de usuario. Ello se consigue siguiendo los pasos que pueden verse arriba.

Como puede apreciarse, la mayoría de los controles presentes en un form tienen la propiedadOnClickEvent asociada. Esa propiedad permite especificar un evento a dispararse cuando el usuariohaga clic sobre el control. Podrá ser un evento del sistema (Refresh, Enter) o uno definido por el usuario.

Page 358: Aplicaciones Genexus

342

Web Panels... variables de grid

• Por defecto todas las variables de un grid son Read-Only

• For each line [in grid] o cualquier evento sobre las líneas o columnas (OnClickEvent, Click, DblClick, IsValid, etc): modifica valor por defecto y todas las variables del grid pasan a ser de entrada. Para que algunas sean de salida:

Propiedad: Read Only

3

No así las de la parte fija del web panel. Esas son por defecto de entrada, como ya hemos visto antes para las variables que utilizamos para filtrar los customers mostrados en el grid.

Cómo desplegar datos en un gridPor defecto todo atributo y variable que está dentro de un grid se despliega en ejecución como texto, es

decir que es únicamente de lectura y por consiguiente no puede ser modificado.

Cómo aceptar datos en un gridEs posible aceptar datos en las variables de un grid dependiendo de la programación de los eventos

existentes en el objeto:

1. Si dentro de un evento del web panel se está utilizando el comando For each line, todas las variables que están dentro del grid pasan a ser de entrada. Es posible indicar en este caso cuáles son las variables que no van a poder ser modificadas a través de la propiedad ReadOnly.

2. Si dentro de la fila hay algún control con un evento click, dblClick, etc.. asociado (ó evento de usuario especificado en la propiedad OnClickEvent), sucederá lo mismo.

Page 359: Aplicaciones Genexus

343

Web Panels...ocultar atributos del grid y permitir selección de una línea

Event ‘Select customer’CustomerView.Call( CustomerId )

endevent

3

Seguimos ampliando nuestro ejemplo; ahora queremos que el usuario pueda seleccionar una línea del grid (un cliente) y presionando botón ‘Select customer’ poder invocar al web panel que habíamosimplementado antes.

En este ejemplo vemos dos funcionalidades en juego:• La necesidad de colocar una columna en el grid oculta (no visible).• Permitir que el usuario seleccione una línea del grid para hacer algo con ella.

¿Por qué colocar la columna correspondiente a CustomerId y ocultarla, en lugar de no agregarla en absoluto? Reflexione sobre lo siguiente: el atributo CustomerId enviado por parámetro al ejecutarse el evento ‘Select customer’, ¿de dónde es extraído? ¿De la base de datos? No, es el que está cargado en el grid. Más específicamente, por cada grid existirá un archivo temporal que contendrá tantas columnascomo las del grid, visibles y ocultas. Cuando el usuario selecciona en el grid la segunda línea, y presiona el botón ‘Select customer’, se está posicionado en ese archivo temporal, correspondiente a esalínea (¡y nunca en la base de datos!). Es por esta razón que de no colocar la columna correspondiente a CustomerId en el grid, no estaríamos pasando valor alguno a CustomerView.

Para permitir al usuario seleccionar una línea del grid, alcanza con ‘prender’ la propiedad‘AllowSelection’ del grid.

Page 360: Aplicaciones Genexus

344

Web PanelsPuesta a punto: determinación tabla base

3

Event ‘Activate’For each line in customerGrid

if &select&customer.Load( CustomerId )&customer.CustomerStatus = Status.Active&customer.Save()Commit

endifendfor

endevent

Event ‘Select customer’CustomerView.Call( CustomerId )

endevent

Event customerGrid.Loadif CustomerStatus = Status.OnHold

&select.Enabled = 1else &select.Enabled = 0endif

endevent

3. Eventos: atributos sueltos(fuera de for eachs)

2. Grid: • atributos de las columnas (visibles+invisibles)• propiedad Order• propiedad Conditions• propiedad Data Selector

+

1. Atributos sueltos en el form

+

¿Cómo determina GeneXus una tabla base a recorrer automáticamente para cargar el grid del web panel?

De existir algún atributo en por lo menos uno de los 3 lugares mencionados, GeneXus podrá encontrartabla base. Para determinarla extrae los atributos encontrados allí (parte fija del Form, en el Grid, tantoen sus columnas como en las propiedades Order, Conditions o using Data Selector, y en los eventosprogramados en el selector de Eventos, solamente considerando los atributos que estén ‘sueltos’ dentrodel evento, es decir, no dentro de un comando for each de acceso a la base de datos), y determina la mínima tabla extendida que los contiene. La tabla base de esa extendida, será la recorridaautomáticamente y cargada con el Load.

Observemos que solamente hemos programado el evento Load para tomar la decisión para cada línea a ser cargada en el grid, acerca de si se habilitará o no para la misma la variable &select que permitirá al usuario marcar el check box.

Importante: La forma de determinación de la tabla base de un grid dependerá de si existe otro grid en el web panel o es el único. El resumen presentado aquí corresponde a un único grid. En este caso se dice que el propio Web panel tiene tabla base. Es la del grid. Cuando existan más de un grid en el web panel, esto ya no tendrá sentido, y cada grid pasará a tener o no tabla base. Veremos la forma de determinación de las tablas bases en ese caso, cuando tratemos el caso de múltiples grids en un web panel.

Page 361: Aplicaciones Genexus

345

Web Panels 4

Para exhibir múltiples registros: Grid (sin tabla base)...

Mostrar el total de facturas por día (pudiendo filtrarse entre dos fechas dadas)

Cada línea del grid no corresponde a cada registro de la tabla INVOICE, sino que agrupa todas las facturas de una fecha y las suma...si fuera un pdf, lo implementaríamos:

For each order InvoiceDatewhere ...

&InvoiceDate = InvoiceDate&Amount = 0for each defined by InvoiceDate

&Amount += InvoiceAmountendforprint InvoiceInfo

endfor

Aquí presentamos otro ejemplo, para observar un caso en el que surge naturalmente la necesidad de implementar un grid sin tabla base.

El caso natural de implementación de un grid con tabla base, es cuando se quiere cargar por cada registro de una tabla, una línea del grid (1 registro – 1 línea). Cuando el caso es que se quiere cargar una línea del grid como producto de recorrer varios registros de la base de datos (N registros – 1 línea), como productos de cálculos, etc., suele ser más natural implementar el grid sin tabla base.

Este es el caso del ejemplo: no queremos cargar por cada factura una línea, sino que queremos agrupar facturas por fecha, y por cada grupo, cargar una línea que sumariza sus Amount. Estamos hablando de un corte de control. Si tuviéramos que implementar un listado PDF en lugar de un web panel, sabríamos bien cómo programarlo (como lo hacemos arriba). Veamos cómo implementarlo con un web panel...

Page 362: Aplicaciones Genexus

346

Web Panels 4

Para exhibir múltiples registros: Grid (sin tabla base)...

No hay atributos (en ninguno de los 3 puntos anteriores) no hay tabla base

GeneXus no puede inferir carga automática: hay que programarlaevento Load ocurre 1 sola vez

Orden de carga de una línea en el grid (con los valores que en ese momento asuman las variables)

El objetivo del comando LOAD es agregar una línea en un grid. Es necesario cuando el grid no tiene tabla base, dado a que en ese caso no se agregará automáticamente línea alguna. El evento Load ocurrirá una vez, y si éste no se programa, el grid resultará vacío. Por tanto en este caso es indispensable programarlo, de acuerdo a la lógica que corresponda. Una vez que se haya asignado valor a cada variable, y se desee agregar una línea al grid, deberá ejecutarse el comando LOAD.

Solamente se puede especificar el comando LOAD dentro del evento Load del grid de un web panel.

Obsérvese que este caso es el que deja más a cargo del analista la implementación. Frente al caso de grid con tabla base, en este GeneXus realiza muchas menos inferencias.

Page 363: Aplicaciones Genexus

347

Web Panels 4

Para exhibir múltiples registros: Grid (sin tabla base)...

¡Refresh no es automático! Agregamos botón asociado a evento Enter o de usuario, sin código, o directamente al Refresh.

En el caso de un grid sin tabla base, los filtros sobre los datos a mostrar son programados dentro del código que implementa la carga (el del Load). Aquí no habrá refresh automático. Esto es, cuando el usuario modifique los valores de las variables que intervienen en los filtros, GeneXus no detectará que debe volver a cargar el grid. Para ello deberá, por ejemplo, agregarse un botón asociado al evento Enter, o a un evento de usuario, sin código, debido a que solo lo necesitamos para que se produzca un Refresh, es decir para que se vuelva al servidor a cargar el web panel.

Sobre los eventos disponibles y el orden en que se disparan, entraremos en lo que sigue.

Page 364: Aplicaciones Genexus

348

Web PanelsProgramación dirigida por Eventos

• Evento Start• Evento Refresh• Evento Load• Evento Enter• Eventos de Usuario• Evento TrackContext (no lo veremos en el curso)

• Asociados a controles del form (dependiendo del tipo de control):• Evento Click, DblClick, RightClick, IsValid, Drag, Drop, etc.

Nota:Refresh, Enter, de Usuario:pueden asociarse a controles del forma través de propiedad OnClickEvent

En todo Web panel existen eventos del sistema que pueden programarse. Algunos ocurrirán siempre, en cada ejecución del web panel (como el Start, Refresh, Load), otros si se los declara y el usuario realiza las acciones necesarias para provocarlos (Enter, definidos por el usuario, TrackContext).

Asimismo, casi todos los controles que aparecen en el form brindan la posibilidad de disparar un evento cuando el usuario hace clic con el mouse sobre ellos (aparecen como hipervínculos en ejecución); se consigue de dos maneras distintas:

1. Editando las propiedades del control (F4), y definiendo un evento de usuario en la propiedad OnClickEvent, o asociándole el evento Enter o el Refresh.

2. Dándole un nombre al control y en la sección de Eventos programando:

Event nombreControl.click…

Endevent

Con esta última alternativa no tendremos que definir un evento de usuario, sino que estaremos programando el evento click del control. Lo mismo ocurre con los eventos DblClick, RightClick, IsValid... (para cuando se hace doble clic, botón derecho, etc.).

Sobre los eventos asociados a las acciones sobre los controles (click, dblclick, drag, drop, etc.) no nos explayaremos en el presente curso. En nuestro wiki encontrará información detallada, así como en el Help de GeneXus.

Sobre el evento TrackContext solo mencionaremos que será posible detectar cambios en el valor dado a un control (grid, variable, etc.) y en ese caso disparar este evento para en base al valor modificado, tomar una acción.

Page 365: Aplicaciones Genexus

349

• Es un evento del sistema, que ocurre automáticamente siempre que se hace Get o Post y es el primer evento que se ejecuta.

• No se conocen valores de atributos, salvo los recibidos por parámetro. Esto se debe a que aún no se ha efectuado la consulta.

• Ejemplo: se puede utilizar para que un control del form no aparezca visible, para cargar un bitmap, para asociarle un Link a otro control, etc.:

Event Start&var.Visible = 0&Update = LoadBitmap("images/edit.gif")newControl.Link = Link(TCustomer)

endevent

Web PanelsEvento Start

Page 366: Aplicaciones Genexus

350

Web PanelsEvento Refresh – Evento Load

• Eventos del sistema, codificables, asociados a la carga del Web Panel. Se ejecuta primero el Refresh y a continuación siempreel Load.

• Si el grid tiene tabla base

• Si el grid no tiene tabla base

Load se ejecuta N veces: una por cada línea

Load se ejecuta 1 sola vez: Dentro del evento habrá que programar la carga de cada línea del grid. Para cargarla, comando Load.

Cuando el web panel es con tabla base, al producirse el evento Refresh se accede a la base de datos, a esa tabla base (la asociada al web panel), y se la recorre cargando los registros que cumplan las condiciones (conditions del grid y generales). Ocurrirá en ese proceso un evento Load por cada registro en el que se esté posicionado, inmediatamente antes de cargarlo. Esto nos permite realizar alguna operación que requiera de ese registro (y de su extendida), antes de efectivamente cargarlo en el grid. Inmediatamente luego de ejecutado el código asociado al evento Load, se cargará la línea en el grid y se pasará el puntero al siguiente registro de la tabla base, para realizar lo mismo (evento Load, carga de la línea). Este proceso se repetirá hasta cargar todas las líneas del grid.

Si un web panel es sin tabla base, GeneXus no puede determinar automáticamente una tabla de la base de datos a recorrer para mostrar la información que se presenta en el form. En este caso en el formsolamente aparecen variables (y no atributos) y también ocurrirán los eventos Refresh y Load, sólo que el evento Load se ejecutará una única vez, dado que no se estará posicionado en ningún registro de ninguna tabla. Dentro de ese evento habrá que codificar la carga, que podrá requerir acceder a la base de datos (ej: comando for each) o no (supóngase que se desea cargar el grid con información obtenida de recorrer un SDT collection, tras efectuar alguna transformación sobre sus items... o cargar líneas en el grid producto de cálculos). El control de la carga del grid, queda aquí en manos del analista, utilizando el comando Load. Este comando solo es válido dentro del evento de igual nombre. Obsérvese cómo en el caso de grid con tabla base, este comando se torna innecesario.

Page 367: Aplicaciones Genexus

351

Web PanelsRefresh automático

• Solo válido para Grid con tabla base

• Para Grid sin tabla basenecesariamente hay que asociar evento

Estudiemos con más detalle la propiedad Automatic Refresh que se encuentra a nivel del Web Panel puede tomar los siguientes valores:

• When variables in conditions change (valor por defecto): luego de provocarse automáticamente el refresh, se dispara el evento Load cargándose el grid según los nuevos valores de las variables.

• No: para que el contenido del grid se refresque luego de cambiar los filtros, el usuario debe realizar una acción:

Si el grid es con tabla base:• Los cambios en las variables de los filtros se detectan automáticamente. • Al presionar la tecla Enter, se dispara el Refresh de la página (no el código del evento

Enter, aunque esté programado).• Al hacer click en un botón o en una imagen asociados a un evento de usuario,

inmediatamente después de cambiar el valor de una variable de las conditions del grid, se ejecuta este evento e inmediatamente a continuación el Refresh de la página. Si el evento fuera el Enter, este evento NO se ejecuta.

Si el grid es sin tabla base:• Los cambios en las variables de los filtros NO se detectan automáticamente • El usuario debe hacer clic en un botón o en una imagen asociados a un evento

Refresh o a un evento de usuario que invoque a un Refresh.

Page 368: Aplicaciones Genexus

352

Web PanelsEventos – Orden de disparo

• Start• Lectura de variables en pantalla• Evento enter o de usuario (click,

dblclick, etc., que produjo post)• Refresh• Load

• POST: Resto de las ejecuciones del web panel.

• GET: Cuando el Web Panel se abre.

• Start• Refresh• Load

Los eventos que se disparan y su orden depende de si se está abriendo el web panel (Get) o si ya estaba abierto y se está efectuando una acción posterior, como presionar un botón (Post).

Arriba mostramos con ejemplos el caso general.

1a. vez: Start + Refresh + Load N-ésima vez: Start + Lectura de variables de pantalla + Evento que produjo el Post + Refresh + Load.

Este es el caso general... existe una excepción...

Page 369: Aplicaciones Genexus

353

Web PanelsEventos – Orden de disparo

• Excepción:• Algunos eventos de usuario deben ejecutarse en el Server pero para

otros no existe necesidad se ejecutarán solamente en el Cliente (sin ejecutarse todos los otros eventos del server: Start, Refesh y Load).

• Evitando roundtrips innecesarios al servidor, y reduciendo la cantidad de datos que viajan de un lado a otro.

• Ejemplo: un evento que cambia el estado de un control, no necesita ejecutarse en el server.

• GeneXus tiene la inteligencia para determinarlos. Es transparente para el programador.

Event ‘UserEvent’&CustomerId.Visible = 0

endevent

Internamente GeneXus determina las entradas y salidas de cada evento. Si en sus entradas, se requiere de acciones ejecutadas en el Server, entonces el evento se ejecutará en el Server. Por ejemplo, si entre las entradas de un evento de usuario se encuentra alguna de las salidas del evento Start (del server), entonces el evento de usuario se ejecutará en el Server.

Si el código del evento no requiere que se ejecute en el servidor, entonces por performance, se ejecutará en el cliente, como código javascript.

De todas maneras el analista GeneXus no deberá preocuparse de estos asuntos, dado que en todo caso será GeneXus quien tendrá la inteligencia de resolver dónde ejecutar el evento.

Page 370: Aplicaciones Genexus

354

Web PanelsMúltiples grids – Grids paralelos

filtrar facturas por día del cliente

Aquí presentamos un ejemplo que reúne los dos casos que veníamos estudiando: el web panel mostrado en ejecución tiene dos grids paralelos: uno que muestra información de los clientes del sistema, y otro que muestra facturas, totalizadas por día. En nuestro caso, querremos además relacionar los datos, de manera tal que si el usuario selecciona un cliente, se le muestren solo las facturas de ese cliente. Incluso al establecer filtros de fechas, también querremos que valgan para el cliente seleccionado (y no para todos los clientes).

Cuando un web panel contiene más de un grid en su form, GeneXus no determina una única tabla base asociada al web panel, sino una tabla base asociada a cada grid.

Atributos que participan en la determinación de la tabla base de cada grid:

• Los incluidos en el grid (se tienen en cuenta tanto los atributos visibles como los no visibles)• Los referenciados en Order y Conditions locales al grid

A diferencia de lo que sucedía para un web panel con un solo grid, en el caso de múltiples grids los atributos de la parte fija del web panel no participan en la determinación de la tabla base de ninguno de ellos, pero deberán pertenecer a la tabla extendida de alguno (para que sea posible inferir sus valores). De no respetarse esto, al especificar al web panel, se mostrará en el listado de navegación resultante, una advertencia informando de esta situación.

Los atributos utilizados en los eventos del web panel tampoco participan en la determinación de la tabla base de ninguno de los grids. Los atributos que se incluyan en los eventos fuera de comandos for each, deberán pertenecer a la tabla extendida de alguno de los grids (al igual que los de la parte fija).

Page 371: Aplicaciones Genexus

355

Web PanelsMúltiples grids – Grids paralelos

Event Start&Customer.Visible = 0

endevent

Event ‘Select customer’&CustomerId = CustomerId

endevent

Event inoicesGrid.Loadfor each order InvoiceDatewhere InvoiceDate >= &startDate when...where InvoiceDate <= &endDate when...where CustomerId = &customerId when

not &customerId.IsEmpty()...

endevent

GeneXus no relaciona las cargas

Este web panel podría haberse implementado de varias maneras distintas, dando por resultado la misma ejecución.

La implementación más natural es la que podemos ver arriba: el primer grid tiene tabla base y el segundo no. Pero podría haberse implementado al revés, con variables en el primer grid y teniendo querealizar la carga de los clientes a mano en el Load, y atributos en el segundo grid, y algunas cosas máspara lograr el corte de control, siendo un grid con tabla base. O cualquiera de las otras dos combinaciones (ambos grids con tabla base, o ninguno con tabla base).

Lo importante es, una vez elegida la implementación más natural al caso, realizarla correctamente.

En cualquiera de los casos, aunque la información a cargar en un par de grids se encuentre relacionadaen la base de datos, GeneXus no asumirá ninguna relación entre los datos a la hora de cargar un grid y el otro. Es análogo al caso de un par de for eachs paralelos en el Source de un procedimiento.

Como puede verse arriba, al web panel en el que teníamos el grid con los clientes, le hemos agregadola parte de visualización de facturas por fecha que habíamos implementado en web panel aparte. Perono alcanza con simplemente unir ambos web panels... para poder relacionar las cargas de los grids, deberemos agregar cierta lógica. En nuestro caso deseamos que una vez que se seleccione un clientedel primer grid, las facturas que se carguen en el segundo no sean las de todos los clientes, sino las del seleccionado.

Para ello debimos hacer dos cosas: agregar una variable &CustomerId para almacenar el id del clienteseleccionado al presionar ‘Select customer’, y luego agregar un filtro por el valor de esa variable cuandose carga el grid de Invoices. Asimismo tuvimos necesariamente que colocar esa variable en el form paraque todo funcione como esperamos... y la razón la encontraremos en el análisis que sigue.

Page 372: Aplicaciones Genexus

356

Web PanelsMúltiples grids – Grids paralelos

1ª. ejecución

Start oculta &customerId

Refresh

customerGrid.RefreshcustomerGrid.LoadcustomerGrid.Load

....

invoicesGrid.RefreshinvoicesGrid.Load

Analicemos lo que sucede cuando se ejecuta este web panel por primera vez.

Primero se ejecuta el evento Start, que en nuestro caso oculta la variable &CustomerId.

Luego, como puede apreciarse en la imagen, se produce un evento Refresh genérico, luego del cuál se producirán las cargas de todos y cada uno de los grids que se encuentren en el web panel, de izquierdaa derecha de arriba a abajo.

Por cada uno ocurrirá un evento Refresh propio y el evento Load (N veces si el grid tiene tabla base, 1 sola si no la tiene).

Obsérvese que en nuestro caso, el grid de clientes tiene condiciones para cargarse, por las variables de filtro &customerName y &countryName, pero al estar vacías no aplican (dado que ambas cláusulascondicionales tienen when not &var.IsEmpty())

El segundo grid es sin tabla base, pero como ya vimos, el evento Load ejecutaba un for each con cláusulas where, por tanto se cargarán solo aquellas líneas para las que se cumplan sus condiciones. Estas son tres:

where InvoiceDate >= &startDate when not &startDate.IsEmpty()where InvoiceDate <= &endDate when not &endDate.IsEmpty()where CustomerId = &customerId when not &customerId.IsEmpty()

Obsérvese que en esta primera ejecución &customerId estará vacío, por lo que no se aplicará este filtroy se cargarán todas las facturas por día, de todos los clientes.

Page 373: Aplicaciones Genexus

357

Web PanelsMúltiples grids – Grids paralelos

2ª. ejecución Seleccionar un cliente:Start oculta &customerId

Refresh

customerGrid.RefreshcustomerGrid.LoadcustomerGrid.Load

....

invoicesGrid.RefreshinvoicesGrid.Load

Lectura de variables de pantallaEvento que produjo post

Event ‘Select customer’&CustomerId = CustomerId

endevent

Luego el usuario selecciona del grid el cliente correspondiente a la segunda línea y presiona el botón ‘Select customer’.

Se detecta una acción, y se realiza un post al servidor, quien ejecuta el Start (ocultando la variable), luego lee las variables en pantalla (&customerId por ahora está vacía, pero no sólo son consideradas variables de pantalla las variables definidas, sino, por ejemplo, la información completa de la línea seleccionada por el usuario con el mouse, entre ella, el valor de CustomerId, columna del grid), luego ejecuta el código del evento que produjo el post, en nuestro caso, ‘Select customer’. Aquí la variable &customerId toma el valor del CustomerId de la línea elegida. Luego se produce el Refresh general que dispara el Refresh y Load de cada grid.

Por tanto, cada grid se carga ejecutando las conditions. El primero se carga igual que antes, porque ninguna de sus conditions ha variado. El segundo, ahora sí tiene un valor para &customerId, por lo que se mostrarán solamente las facturas del cliente.

Uno podría preguntarse por qué se tuvo la necesidad de colocar la variable oculta en el form. Por quésimplemente no podía usársela como variable dentro del programa, sin necesidad de colocarla y hacerla invisible. Con esta segunda ejecución todavía no podemos contestar la pregunta. De hecho, si se analiza, puede verse fácilmente que hubiésemos obtenido el mismo comportamiento si sólo le asignábamos valor a la variable en el ‘Select Customer’ sin colocarla en el form.

La razón surgirá claramente con la siguiente ejecución...

Page 374: Aplicaciones Genexus

358

Web PanelsMúltiples grids – Grids paralelos

3ª. ejecución Filtrar facturas para el cliente seleccionado

Start

Refresh

customerGrid.RefreshcustomerGrid.LoadcustomerGrid.Load

....

invoicesGrid.RefreshinvoicesGrid.Load

Lectura de variables de pantalla

Evento que produjo post (vacío)

&customerId invisible

Ahora el usuario ya tiene seleccionado el segundo cliente, y lo que desea es filtrar sus facturas por fecha (no quiere visualizarlas todas).

Para ello especifica los filtros de fecha, y presiona el botón ‘Search’, que producirá un post al servidor.Entonces se ejecutará el Start con su código, luego se leerán las variables de pantalla: aquí está la razón de haber colocado &customerId en el form. Se leerá entonces el valor de &customerId, que permanecerá incambiado hasta tanto el usuario no vuelva a seleccionar otro cliente del grid y presionar el botón ‘Select customer’... esta variable presente en el form, es la forma de mantener la memoria entre ejecuciones.Recuérdese que cada vez que se hace un post al servidor, es una nueva ejecución del web panel, por lo que las variables comienzan nuevamente vacías. Es por ello que el segundo paso: “Lectura de variables de pantalla” es fundamental.Ahora sí, siguiendo con el ejemplo, se lee de pantalla la variable &customerId invisible, junto con las variables visibles &startDate y &endDate. Y luego, como siempre, se ejecuta la carga (Refresh genérico + Refresh y Load de cada grid).Han cambiado las condiciones del for each que carga el segundo grid, por lo que ahora aparecerán solamente las facturas del segundo cliente, entre las fechas estipuladas por el usuario.

Si ahora el usuario quiere cambiar de cliente, para ver sus facturas, lo seleccionará del grid de clientes y presionando ‘Select Customer’, el proceso volverá a empezar como vimos en la 2da. ejecución.

¿Y cómo se vuelve a trabajar con las facturas de todos los clientes y no con las de uno dado? Piense qué pasará si el usuario no selecciona ningún cliente del grid con el mouse, pero presiona ‘Select Customer’. El valor de la variable &CustomerId quedará vacío, pues CustomerId no tendrá valor.

Por este motivo, al botón ‘Select Customer’ podríamos haberle llamado ‘Select/Unselect’.

Page 375: Aplicaciones Genexus

359

Web PanelsGrid - Propiedades

• Paginado automático: GeneXus realiza un paginado automático si la propiedad Rows tiene un valor distinto de 0.

Inserta automáticamente los botones de paginado.

Los botones que se insertan dependen de la cantidad de registros a mostrar y la cantidad de líneas del grid.

Page 376: Aplicaciones Genexus

360

Web PanelsGrid – Ordenamiento automático de las columnas

Las columnas pueden ser ordenadas sin necesidad de programar ningún código adicional: clic sobre el título de la columna.

Se ordena la página del grid cargada, por lo que no compite con el Order programado a nivel del grid.

Esta funcionalidad es válida para grids en transacciones y en web panels.

Page 377: Aplicaciones Genexus

361

Web PanelsTipos de grids

• Grid estándar: Datos repetitivos en formato fijo (filas y columnas)

• Grid Free Style: Datos repetitivos en formato libre.

• Tabla con registros repetitivos

• No posee títulos para las columnas

• Permite tener más de un tipo de control en una misma celda

Se dispone de dos tipos de grids:

• Grid estándar: el que vimos hasta ahora, en transacciones y web panels• Grid Free Style

Estos grids agregan potencia al diseño de aplicaciones web, permitiendo al desarrollador mayor libertad a la hora del diseño.

El grid Free Style permite al usuario definir el formato de los datos a desplegar de una forma menos estructurada que el grid estándar.

El grid Free style es básicamente una tabla a la que se le pueden insertar los atributos/variables, textblocks, imágenes, botones, web components, embedded pages, grids freestyle y/o grids que se van a mostrar posteriormente en la pantalla. En este caso para poder visualizar las propiedades hay que seleccionar la tabla donde se encuentran los atributos/variables.

En el ejemplo presentado arriba queremos mostrar alguna información de los países. El atributo CountryFlag se ha incluido en la transacción ‘Country’ para almacenar la foto de la bandera de cada país (es un atributo de tipo Blob). Pero no queremos mostrar la información como lo haríamos en un gridestándar, con cada elemento de información en una columna distinta del grid. Aquí queremos mostrar la foto y debajo el nombre del país.

El comportamiento de las variables dentro de un grid Free Style es análogo al que presentan dentro de un grid estándar, por lo tanto también quedan de ingreso si existe un For each line dentro de algún evento, o si se asocia un evento a cualquier control de la fila. Nuevamente este comportamiento puede modificarse, cambiando la propiedad Read Only.

Page 378: Aplicaciones Genexus

362

Web PanelsMúltiples grids – Grids anidados

Ejemplo: Desplegar todos los países con sus respectivos clientes, y cantidad de clientes.

Grid1: Free Style.

Grid2: estándar

Trn Country

{

CountryId*

CountryName

CountryFlag

}

Trn Customer{

CustomerId*

CustomerName

CustomerAddress

CountryId

CountryName

}

Tabla base Grid1: COUNTRY

Tabla base Grid2: CUSTOMER

Este caso de grids anidados es como el de for eachs anidados en el caso de un procedimiento: esto es, aquí sí se relacionan las cargas, y se cargarán por tanto en el Grid2, todos los clientes pertenecientes al país cargado en el Grid1 en cada oportunidad.

De hecho, el orden de ejecución de los eventos estará anidado:

Refresh (genérico)Grid1.Refresh

Grid1.Load carga de un paísGrid2.RefreshGrid2.Load carga de cliente del paísGrid2.Load carga de cliente del paísGrid2.Load carga de cliente del país

Grid1.Load carga del siguiente paísGrid2.RefreshGrid2.Load carga de cliente del paísGrid2.Load carga de cliente del paísGrid2.Load carga de cliente del país

.....

Page 379: Aplicaciones Genexus

363

Web PanelsGrid Free Style

(Ejemplo: Continuación)

Propiedades

Grid Free Style

Page 380: Aplicaciones Genexus

364

Web PanelsTipos

• Tipos de Web panels• Component• Web Page• Master Page

• Propiedad Type

Los objetos web pueden ser definidos con tres tipos diferentes, configurable en la propiedad Type del objeto. Para un web panel podrá tomar uno de los valores:

• Component: (transacción ó web panel, que a partir de aquí podrá ser incluido en otro web object –transacción o web panel)• Web Page (es decir, el objeto será una transacción ó web panel tal como hemos trabajado hasta el momento)• Master Page

A continuación introduciremos el Web Panel tipo: “Component” y luego volveremos sobre el “Master Page” pero no lo veremos en profundidad en este curso.

Page 381: Aplicaciones Genexus

365

Web PanelWeb Component

Ya teníamos programado un web panel ‘CustomerView’que mostraba los datos del cliente Reutilicémoslo

Un component es un web panel pero que se va a ejecutar dentro de otro.

Page 382: Aplicaciones Genexus

366

Web PanelsWeb Component

Page 383: Aplicaciones Genexus

367

Web PanelsWeb Components

Ejemplo: Crear un nuevo tab en la instancia de Pattern Work ‘With Countries, mostrando los clientes por cada país.

1) Definir el Web Panel CustomersPerCountry como Component

2) Definir el nuevo tab CustomersPerCountry en la instancia de Pattern Work With Countries

El Web Panel CustomersPerCountry recibe CountryId como parámetro.

Page 384: Aplicaciones Genexus

368

Web PanelsWeb Components

Page 385: Aplicaciones Genexus

369

Web PanelsMaster Pages

El otro tipo de Web Panel que ya vimos es la Master Page, que centraliza layout y comportamiento común, en un solo objeto y permite reutilizarlo en todo otro objeto sin tener que programar.

Creadas automáticamente con la KB

control dentro del que se cargarán las páginas

Tener un look & feel consistente es hoy en día un deber de toda aplicación Web.Crear y mantener cada página de una aplicación Web asegurando la consistencia con el resto del sitio toma gran tiempo de programación.

Al crear una base de conocimiento, GeneXus X creará también dos objetos de tipo Master Page:• ApplMasterPage: Para la aplicación.• PromptMasterPage: Para los prompts.

Se creará un web panel, ApplMasterPage categorizado como “Master Page” con todo lo que sea el Layout y comportamiento común a todas las páginas del sitio, y en el mismo se dejará un espacio para cargar en cada oportunidad la página que corresponda (el contenido variable del sitio). Corresponde al control especial ContentPlaceholder. Las páginas web que implementan el contenido variable, se implementan como Web Panels o Web Transactions comunes y corrientes (es decir de tipo “Web Page”), y se asocian a la Master Page(a través de la propiedad de igual nombre), de manera que cada vez que se ejecuten, se carguen con ese “contexto”. Abra cualquier objeto GeneXus con form (transacción o web panel) creado en una KB, y vea el valor de la propiedad Master Page.

Las Master Pages proveen una forma de centralizar el layout y el comportamiento común en un solo objeto y reutilizarlo en todo otro objeto sin tener que programar. Esto significa que la modificación de alguna parte del layout o del comportamiento común es tan fácil como modificarla en un único objeto y ¡listo!.

En una misma base de conocimiento se pueden definir tantas Master Pages como se desee.

Page 386: Aplicaciones Genexus
Page 387: Aplicaciones Genexus

370

Gxflow

Page 388: Aplicaciones Genexus

371

GXFLOWBreve introducción teórica

• ¿Qué es un workflow?• Un set de tareas ordenadas en una secuencia determinada, que define un 

proceso en el cual las situaciones son resueltas o bien manualmente o automáticamente.

• Ejemplo

En el ejemplo se está mostrando un workflow que se sigue en una empresa que vende mercadería “al por mayor”.

Se pueden observar claramente las tareas consecutivas que se siguen para llevar a cabo el proceso de venta.

Page 389: Aplicaciones Genexus

372

• ¿Por qué recomendamos incluir tecnología de workflow dentro de nuestras soluciones GX?

Porque todo sistema que querramos construir para una empresa, en el 99% tendrá procesos de negocios para modelar, gestionar y hacerlesseguimiento…

- conjuntos de tareas ordenadas- responsables- cronogramas, alertas, tiempos máximos ...

y el manejo y seguimiento de todo esto está hecho: Lo provee Gxflow

GXFLOWBreve introducción teórica

Page 390: Aplicaciones Genexus

373

GXFLOWBreve introducción teórica

• Gxflow es una herramienta integrada a GeneXus que nos permite y brinda:

• Modelar los procesos de la empresa

• Definir seguridad

• Definir calendarios, alertas, deadlines

• Etapas de Modelado y Desarrollo de aplicación operativa integradas

• Etapa de ejecución que brinda proactividad

• Auditoría

• Claridad para capacitar nuevos miembros y para mostrar a clientes

Gxflow es una herramienta integrada a GeneXus que nos permite y brinda:

1) Modelar los procesos de la empresa: Diagramar los procesos nos da la ventaja de poder cambiarel orden de sus tareas, quitar o incluir tareas nuevas y/o cambiar las condiciones de su ejecución, sin tocar el código de los objetos mismos.

2) Definir seguridad: Se definen roles y cuáles pueden ejecutar qué tareas. Esto evita tener que incluir código para la seguridad en los objetos.

3) Definir calendarios, alertas, deadlines

4) Etapas de Modelado y Desarrollo de aplicación operativa integradas: En GeneXus X es muy práctico y sencillo relacionar los objetos GeneXus desarrollados que implementan la aplicación operativa con los diagramas que modelan los procesos. Veremos como se arrastran los objetos a los diagramas y lo práctico que resulta tener el modelado de los procesos integrado con el desarrollo de la aplicación operativa.

5) Etapa de ejecución que brinda proactividad: Cada usuario al ejecutar, de primera verá las tareas que tenga para hacer (no tendrá que buscar en la aplicación el trabajo pendiente).

6) Auditoría: GXflow permite ver en qué está cada usuario, cuánto tiempo le lleva cada tarea, etc.

7) Mejor entendimiento: para un nuevo miembro del equipo trabajo, y también para hacer muestras a los clientes.

Page 391: Aplicaciones Genexus

374

INTERCALADOS

• Crear objetos GeneXus que describen realidad y procesos

• Crear diagramas de procesos de negocios para modelar los procesos

• Asociar objetos GeneXus a diagramas de procesos de negocios

• Ejecutar proceso

GXFLOWBreve introducción teórica

• Pasos a seguir para trabajar con GXflow:

Page 392: Aplicaciones Genexus

375

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• ¿Cómo crear un diagrama de proceso de negocio?

• Creando un objeto en la KB de tipo Business Process Diagram

• ¿Cuántos diagramas de procesos de negocios definiremos en nuestra KB?

• Tantos como procesos se tengan en la empresa

Page 393: Aplicaciones Genexus

376

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Definición paso a paso.. (1)

Page 394: Aplicaciones Genexus

377

ARRASTRANDO ESTOS SÍMBOLOS SE CONFECCIONA DIAGRAMA

TAREA / ACTIVIDAD INTERACTIVA

TAMBIÉN SE PUEDE ARRASTRAR AL DIAGRAMA TAREA / ACTIVIDAD INTERACTIVA DESDE“FOLDER VIEW”

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Definición paso a paso.. (2)

Si desde “Folder View” se arrastra un objeto transacción o web panel al diagrama, se estará agregandouna “tarea / actividad interactiva” al flujo, y la misma ya quedará con dicho objeto asociado para la etapa de ejecución. También dicha “tarea / actividad interactiva” agregada al diagrama, quedaráautomáticamente nominada con el mismo nombre que la transacción o web panel que fue arrastrado.

Si en cambio se agrega una “tarea/actividad interactiva” al diagrama arrastrando el símbolocorrespondiente desde la toolbox disponible para confeccionar diagramas de procesos de negocios, luego será necesario asociar a dicha tarea un objeto transacción o web panel definido en la KB. Para ello, simplemente después de haber agregado la tarea en el diagrama y teniéndola seleccionada, habrá que editar sus propiedades (F4 para abrir el diálogo de propiedades) y completar la propiedadWeb Application con el objeto que corresponda, así como la propiedad Name con el nombre que se le quiera dar a la “tarea/actividad interactiva”.

Page 395: Aplicaciones Genexus

378

INICIO DE PROCESO

ACTIVIDAD/TAREA INTERACTIVA

ACTIVIDAD/TAREA BATCH

FIN DE PROCESO

EN ESTE PROCESO QUE SE ESTÁ MODELANDO, OTRO PROCESO ES REUTILIZABLE COMO SUBRPROCESO

CONDICIÓN PARA EVALUAR… Y SEGÚN RESULTADO, SE SEGUIRÁ UNA RUTA U OTRA

VIENEN VARIAS RUTAS HASTA ESTE SÍMBOLO Y RECIÉN AL LLEGAR TODAS A ESTE PUNTO, EL FLUJO CONTINÚA

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Descripción de símbolos

No se describirán todos los símbolos disponibles en la toolbox de workflow, sino los símbolos básicosque debemos conocer en un principio.

Símbolo: Condición

Cuando se está modelando un diagrama de proceso y en determinada parte del flujo de actividades se necesita evaluar una condición para que dependiendo de si se cumple o no, se siga con cierto flujo de actividades u otro, es que contamos con el símbolo de condición.

Page 396: Aplicaciones Genexus

379

Bastará con agregar un símbolo de condición (rombo verde) al diagrama (conectado desde la actividad previa) y a partir del rombo podrán salir N rutas (que serán de color verde también). Cada una de estas rutas verdes que salgan desde un rombo de condición, deberá tener asociada una condición a ser evaluada (haciendo doble clic en cada ruta verde, se abrirá un editor para ingresar su condición asociada); y en tiempo de ejecución del diagrama, como veremos más adelante, cuando se llegue a la condición en la ejecución del proceso, dependiendo de cuál de las evaluaciones resulte verdadera se continuará con la ejecución de una ruta y su flujo de actividades que le sigue, u otra.

En breve veremos ejemplos de definición de condiciones (sintaxis y posibilidades).

Símbolo: Batch Activity

Permite agregar a un diagrama de proceso de negocio, un proceso batch (por ejemplo un proceso masivo) que se ejecutará en el servidor.

Si se agrega arrastrando el símbolo correspondiente desde la toolbox, luego será necesarioasociarle a dicho proceso batch un objeto procedimiento definido en la KB. Para ello, simplemente después de haber agregado el símbolo de proceso batch en el diagrama y teniéndolo seleccionado, habrá que editar sus propiedades (F4 para abrir el diálogo de propiedades) y completar en la propiedad Procedure el nombre del procedimiento quecorresponda. Asimismo habría que asignarle un nombre en su propiedad Name.

Si en cambio desde “Folder View” se arrastra un procedimiento determinado, se estaráagregando al diagrama como proceso batch que ejecutará en el servidor; y el mismo yaquedará con dicho procedimiento y nombre asociado para la etapa de ejecución.

Page 397: Aplicaciones Genexus

380

Se va confeccionando diagrama deproceso de negocio, arrastrandosímbolos de Toolbox y objetos deFolder View ….

¿QUÉ INFORMACIÓN PODEMOS INVOLUCRAR EN LAS CONDICIONES?

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Definición paso a paso.. (3)

Aquí vemos que hemos ido confeccionando el diagrama de proceso que creamos. Le hemos agregado tareas interactivas y una condición.

Vemos que con doble clic en las rutas verdes que salen de la condición, se abre el editor de condiciones para editar cada condición (así en caso de cumplirse una u otra se seguirá con cierto flujo de actividades u otro).

En lo que sigue veremos el concepto de “Datos Relevantes” que es fundamental para comprender quéinformación podemos involucrar en las condiciones.

Page 398: Aplicaciones Genexus

381

TODO “DIAGRAMA DE PROCESO DE NEGOCIO” TIENE UN TAB PARA LA DEFINICIÓN DE SUS DATOS RELEVANTES

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Concepto fundamental: Datos Relevantes

• El concepto de “Datos Relevantes” se utiliza para mantener un área global de datos en un proceso

• Este concepto permite administrar el pasaje de información entre las tareas y quela información sea conocida en todo el flujo

• Se puede ver como que son “variables globales” en un proceso

Page 399: Aplicaciones Genexus

382

• Cuando se arrastra desde “Folder View” una transacción a un diagrama de proceso, automáticamente se crea un dato relevantecon el mismo nombre e igual tipo de dato que la clave primaria de la transacción:

• También definiremos datos relevantes explícitamente, comoveremos...

AL ARRASTRAR LA TRANSACCIÓN “INVOICE” AL DIAGRAMA, AUTOMÁTICAMENTE SE CREÓ ESTE DATO RELEVANTE

NUESTRO OBJETO DE TIPO “BUSINESS PROCESS MODEL”

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Concepto fundamental: Datos Relevantes (Cont.)

Para los datos relevantes que se definen automáticamente con igual nombre y tipo que las claves primarias de las transacciones (como en este ejemplo: InvoiceId), hay una correspondencia automática entre el dato relevante y el atributo PK.

Esto es, cuando modelamos el diagrama “el dato relevante es el dato global conocido en ese contexto” y en los objetos GeneXus que desarrollamos asociados a las actividades del diagrama “recibimos en parm al atributo PK” (tratándose de la misma información o bien en el contexto del diagrama, o en el contexto del desarrollo de la funcionalidad respectivamente). En otras palabras hay un mapeo automático entre el dato relevante de igual nombre y tipo al de un atributo clave primaria y dicho atributo clave primaria.

Si bien la mayoría de Datos Relevantes en un diagrama de proceso suelen corresponderse con claves primarias, también hay casos en los que surge la necesidad de definir explícitamente otros datosrelevantes. A continuación veremos ejemplos.

Page 400: Aplicaciones Genexus

383

• ¿Cuándo surge la necesidad de definir datos relevantes?

Trn “Invoice”

Web Panel “Authorization”

¿CÓMO CARGO UN VALOR U OTRO EN ESTOS EVENTOS Y QUE EL VALOR CARGADO“SE VEA” EN EL DIAGRAMA PARA EVALUAR CONDICIÓN POSTERIOR?

InvoiceId = Dato Relevanteen el diagrama

Parm(InvoiceId);

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

Inicialmente hemos explicado que cuando trabajamos en GeneXus con workflow, realizamos los siguientes pasos básicamente:

• Crear objetos GeneXus• Crear diagramas de procesos de negocios• Asociar objetos GeneXus a diagramas de procesos de negocios• Ejecutar proceso

Así es que venimos confeccionando un diagrama de proceso en nuestra KB; teníamos previamente definidos algunos objetos GeneXus que hemos arrastrado al diagrama, y vamos desarrollando otros objetos e incorporándolos al diagrama también. Más adelante veremos como asignar roles a las diferentes actividades del diagrama. Por ahora la idea es que contamos en la KB con una transacción “Invoice”, la cual fue arrastrada al diagrama como primer actividad interactiva del proceso y más adelante definiremos que esta tarea interactiva podrá ser ejecutada por las vendedoras de la empresa.

Cuando una vendedora ingrese una venta (a través de la transacción “Invoice”), entrará el cliente, la mercadería solicitada, las cantidades, la forma de pago solicitada por el cliente, grabará la venta con un número interno (no el nro de factura formal) y ahí terminará la primer actividad. Luego esa venta deberáser evaluada por un supervisor (quien evaluará de qué cliente se trata, el monto, la forma de pago), y el supervisor deberá aceptar o denegar la venta. Esta segunda actividad interactiva del proceso fue agregada al diagrama arrastrando el web panel “Authorization”.

Entonces, a nivel del diagrama de proceso contamos con el dato relevante InvoiceId (de igual nombre y tipo de dato que el atributo InvoiceId), lo cual significa que dicho dato se conoce a lo largo de todo el flujo de actividades. Y en lo que se refiere a los objetos GeneXus relacionados al diagrama, el webpanel “Authorization” implementa la 2da actividad del proceso y recibe por parámetro al atributo InvoiceId. En el form del web panel “Authorization” se visualizarán los datos de la factura, el límite de crédito y saldo de límite de crédito del cliente y estará la posibilidad de ver la historia de facturas anteriores del cliente. Este web panel ofrecerá al supervisor 2 botones: “Authorize” y “Refuse”.

Page 401: Aplicaciones Genexus

384

Vale explicar que cuando trabajamos con workflow en GeneXus, en el código de los objetos ya no pondremos invocaciones de un objeto a otro. En cambio, en los diagramas de procesos que confeccionamos ya quedan implícitas las invocaciones entre actividades consecutivas.

Más adelante veremos que en la etapa de ejecución, procederemos a ejecutar una aplicación que nos ofrecerá crear instancias de los procesos que hemos definido (por ejemplo se podrán crear N instancias del proceso de venta definido). Al crear una nueva instancia de proceso, comenzará la ejecución de la primer actividad (se presentará la trn “Invoice” para ello, y si definimos roles, se validará que en particular sea una vendedora quien realice esta actividad). Una vez finalizada la primer actividad, seguirá la segunda actividad (para ser efectuada por el rol que corresponda, que en nuestro ejemplo es un supervisor) y así sucesivamente se irán finalizando actividades de la instancia del proceso y ejecutando las siguientes actividades hasta concluir dicha instancia de proceso.

De modo que no codificamos más calls en los objetos GeneXus, y de necesitar cambiar el orden de precedencias de las actividades en un proceso, o agregar o quitar actividades, así como cambiar las condiciones de ejecución de las actividades, lo reflejamos en el diagrama de proceso sin tocar el código de los objetos.

Algo a hacer notar es que si bien no definimos calls en el código mismo de los objetos, sí definimos regla parm en los objetos GeneXus que participan en un diagrama de proceso. Esto es porque los objetos son invocados -si bien con otro esquema de trabajo del que conocíamos- y necesitan pasarse la información necesaria… así es que suelen recibir por parámetro los atributos claves primarias que son análogas a los datos relevantes en el diagrama de proceso (y que hay una correspondencia entre estos conceptos).

Una vez hechas estas explicaciones, seguiremos estudiando paso a paso la implementación de la segunda actividad del proceso que venimos confeccionando. El web panel “Authorization” recibe por parámetro al atributo InvoiceId, muestra en su form información para la toma de desición de la autorización o denegación y para ello contiene 2 botones “Authorize” y “Refuse” respectivamente.

Si nuestro objetivo es cargar una variable con valor 1 en el evento “Authorize” y con valor 0 en el evento “Refuse”, y queremos que el valor asignado “se vea” en el diagrama de proceso, bastará con realizar lo siguiente:

1) En el tab “Relevant Data” del diagrama de proceso, habrá que crear un dato relevante (por ejemplo de nombre: InvoiceAuthorized) de tipo Numeric.

2) En el web panel "Authorization“ habrá que leer el dato relevante y cargarlo en cada evento del webpanel, así:

Siendo:&wfAuthoriz: una variable definida en el web panel, de tipo de datos es: WorkflowApplicationData&wfProcessInstance: una variable definida en el web panel, de tipo de datos: WorkflowProcessInstance

Page 402: Aplicaciones Genexus

385

1)

En wbp “Authorization”defimos 2 variablesde tipos de datosWorkflowApplicationDatay WorkflowProcessInstancepara leer y cargar datorelevante

Creación explícita de Dato Relevante en Diagrama de Procesoy cómo trabajar con el mismo en objetos

2)

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Definición paso a paso.. (4)

De modo que hemos definido un dato relevante en el diagrama de proceso (de nombre InvoiceAuthorized) y luego en el web panel “Authorization” se lee el dato relevante en variable &wfAuthoriz de tipo WorkflowApplicationData. El tipo de datos WorkflowApplicationData viene a significar “dato relevante”.

También hemos definido en el web panel una segunda variable de tipo WorkflowProcessInstance. El tipo de datos WorkflowProcessInstance viene a significar “instancia de proceso”. O sea que si analizamos la primer línea codificada en cualquiera de los 2 eventos, estamos recuperando en la variable &wfAuthoriz (de tipo “dato relevante”) el valor del dato relevante de nombre ‘InvoiceAuthorized’(entre comillas va el nombre del dato relevante tal como se ha definido en el diagrama de proceso) perteneciente a la instancia del proceso que se está ejecutando.

Luego en la segunda línea codificada en ambos eventos, se está asignando a la variable &wfAuthoriz(de tipo “dato relevante”) el valor 0 o 1 según corresponda (utilizando la propiedad Numeric del tipo de dato WorkflowApplicationData, por estar asignando un valor númerico).

Por último en cada evento se hace return, porque ya se ha recuperado el valor del dato relevante, se le ha cargado el valor deseado y se desea culminar con la ejecución de esta actividad.

De esta manera entonces leemos y cargamos datos relevantes en los objetos GeneXus asociados a las actividades de un diagrama de proceso, empleando tipos de datos workflow, propiedades y métodos.

Sin embargo para datos relevantes con igual nombre y tipo que las claves primarias, esto no es necesario (sino que se reciben por parm los atributos primarios directamente y ya hay mapeo automático con el dato relevante correspondiente).

Page 403: Aplicaciones Genexus

386

En todo el diagrama contamos con elDato Relevante &InvoiceAuthorized...

En rutas que salen de la condiciónevaluamos valor de Dato Relevante&InvoiceAuthorized…

• Definición paso a paso.. (5)

Evaluación de Dato Relevante en condición de Diagrama de Proceso

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

Observe que en cada ruta verde que sale del rombo de condición, se evalúa el valor del dato relevante &InvoiceAuthorized.

Si bien cuando definimos el nombre del dato relevante no incluimos el & (amperson), el diálogo de definición de datos relevantes muestra claramente un ícono &, dando la pauta de que se trata de variables:

De modo que para referirnos a un dato relevante en el flujo, lo referenciamos con & como se puede observar en las 2 imágenes capturadas correspondientes al editor de condiciones. Sin embargo paradatos relevantes con igual nombre y tipo que las claves primarias, es posible referenciar tanto el dato relevante (con &) como el atributo clave primaria directamente.

Page 404: Aplicaciones Genexus

387

1) Se quiere definir atributo InvoiceAuthorized en trn “Invoice” y grabar en cada invoice si fueautorizada o no..

2) En web panel “Authorization” se invoca proc en cada evento, que graba 1 o 0 en atributoInvoiceAuthorized

3) En Diagrama de Proceso el atributo InvoiceAuthorized puede inferirse (a través de InvoiceId) y evaluamos directamente dicho atributo en rutas que salen de la condición

EVALUAMOS ATRIBUTO

(NO DATO RELEVANTE)

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Otra solución posible para resolver pasos (4) y (5)

Con esta solución, no tenemos necesidad de definir Dato Relevante InvoiceAuthorized , ya que tenemos en un atributo la información de si la invoice fue autorizada / denegada… y en el flujo se pueden inferir atributos a través de claves primarias, y evaluar directamente atributos.

Page 405: Aplicaciones Genexus

388

1)

2)

DEFINICIÓN

DE ROLES EN

LA KB

ASIGNACIÓN

DE ROLES

A ACTIVIDADES

EN DIAGRAMA

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Definición de roles

La definición de roles se realiza a nivel de la KB en la sección de Preferences.

Luego seleccionando cada actividad del diagrama y presionando F4, en la propiedad Roles se podráasignar la lista de roles que podrán ejecutar dicha actividad.

Page 406: Aplicaciones Genexus

389

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Diagrama de Proceso completo correspondiente al proceso quevenimos confeccionando:

Si el supervisor autoriza una venta, la siguiente actividad modelada en el diagrama es “InvoiceToBePrepared”. Esta actividad interactiva tiene un web panel asociado que recibe por parámetro al atributo InvoiceId, muestra la información de la venta autorizada y tiene un botón para que la persona de empaque lo presione cuando haya terminado de preparar la mercadería. El evento asociado a ese botón, invocará a un procedimiento que grabará en un atributo de la invoice, un valor indicador (flag) de que el empaque ya se ha realizado.

La siguiente actividad también es interactiva y tiene un web panel asociado que recibe por parámetro al atributo InvoiceId, muestra la información de la venta preparada y tiene un botón para emitir la factura. Cuando una vendedora presione este botón, el evento asociado al botón invocará a un procedimiento que grabará en la invoice el número de factua formal y emitirá la impresión.

La última actividad de este flujo que venimos explicando, corresponde a la distribución de la mercadería. Esta actividad también tiene un web panel asociado que muestra los datos de la venta y presionando un botón, un proc grabará que la misma ha sido entregada.

Las fechas / horarios de efectuadas cada una de las actividades, quedarán registradas durante la ejecución del workflow.

Page 407: Aplicaciones Genexus

390

• Save All• Build All• (Se solicitarán datos de Enviroment)• Run del Diagrama de Proceso

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Pasos para ejecutar:

Page 408: Aplicaciones Genexus

391

GXFLOWConceptos básicos para crear

diagramas de procesos de negocios

• Ejecución:

Hay 2 modalidades de ejecución:

• Prototyper• Full Client

En la sección de Preferences se puede configurar cuál se desea:

Lógicamente la modalidad “Prototyper” está orientada a la etapa de prototipación. Y la modalidad “Full-Client” a etapa de producción.

En etapa de prototipación no nos interesa probar la seguridad, motivo por el cual al ejecutar la aplicación en modalidad “Prototyper” inicialmente se limpian todas las instancias de pruebas anteriores y se permiten ejecutar todas las actividades sin controlar roles.

Al ejecutar la aplicación en modalidad “Full-Client” en cambio, no se aborta nada inicialmente y se requiere crear usuarios (para login) cada uno de ellos con la lista de roles que le corresponda, ya que en este caso sí la seguridad se controlará.

Page 409: Aplicaciones Genexus
Page 410: Aplicaciones Genexus

392

Manejo de versiones

Page 411: Aplicaciones Genexus

393

Manejo de VersionesEl desarrollo de software es un trabajo en equipo y cierto grado de 

confusión es inevitable.

¡No puedo reproducir el error en esta

versión! ¡Este programa

ayer funcionaba!

¿Qué pasó con el arreglo de la

semana pasada? ¿Realmente estamos

trabajando en la última versión?

La aplicación en ejecución no es compatible con el código fuente

Page 412: Aplicaciones Genexus

394

Manejo de VersionesConclusión:

• El ciclo de desarrollo es un proceso dinámico que requiere control de los cambios realizados a los objetos del proyecto.

Se necesita:

• Marcar hitos en el desarrollo de la aplicación

• Tener líneas de desarrollo paralelas

• Administrar el ciclo de vida de la aplicación (SCM)

KBVersión 1 Versión 2 Versión N

. . .

Durante el proceso de construcción de la aplicación, es necesario marcar hitos en el desarrollo de la misma, entendiendo como hitos la “congelación” del desarrollo en un determinado momento especial en el proceso. Esto se puede dar por ejemplo para liberar una versión a producción, congelar una versión entregada a un cliente, la necesidad de congelar un determinado estado especial de la aplicación, etc. Además también vamos a querer tener distintas líneas de desarrollo de la aplicación, algo muy común por ejemplo cuando se quiere hacer variaciones del proyecto para un cliente o cuando se requiere que dos grupos de trabajo lo hagan en paralelo y necesitamos poder realizar una administración de todos estos elementos. Lo que necesitamos básicamente es administrar el “ciclo de vida” de la aplicación durante el desarrollo. Varias de estas funcionalidades entran en lo que en el mundo del software se conoce como SCM (Software Configuración Management)

Page 413: Aplicaciones Genexus

395

Solución: Manejo de versiones de la aplicación

Nodo raíz del árbol de versiones

APPAPP 1.0 1.1 1.2 2.0

1.1.1

1.0.1

2.1

1.1.2

1.0.2 1.0.3

Manejo de Versiones

Se comienza el desarrollo siguiendo una línea principal de desarrollo (línea del medio – Trunk), lugar donde se agregan las funcionalidades requeridas y se utilizan prototipos para probarlas .

En determinados momentos de este ciclo surge la necesidad de establecer un checkpoint en el proceso, ya sea por la liberación de una versión, la entrega de una versión a un cliente, la necesidad de congelar un determinado estado de una aplicación, etc. Entonces lo que hacemos es congelar el producto en ese momento creando por ejemplo la versión 1.0 que se la entregamos a un cliente y se continúa el proceso de desarrollo principal.

En determinado momento surge la necesidad de realizar correcciones sobre la versión entregada al cliente (1.0) por lo que es necesario abrir una nueva línea de desarrollo para incluir estas correcciones sobre lo que era la versión 1.0 sin afectar la línea de desarrollo principal que siguió creciendo desde el momento de la congelación de la versión 1.0.Entonces se crea lo que se conoce como Developmen Version o branch, que es simplemente una nueva línea de desarrollo paralela a la principal.

Luego durante el transcurso del proyecto vuelven a aparecer requerimientos de este tipo, ya sea de determinación de checkpoints como la necesidad de abrir nuevas líneas de desarrollo, entonces por ejemplo creamos la versión 1.1, o la 1.0.1 que vendría a ser un congelado de la línea de desarrollo abierta a partir de la versión 1.0 y así sucesivamente hasta tener por ejemplo la situación planteada en el diagrama.

Estas situaciones forman parte de la operativa normal en el desarrollo de una aplicación y es necesario administrar fácilmente este proceso.

Para ello se introduce el concepto de Manejo de Versiones. Las versiones se clasifican en:

•Development Versions, representan las líneas de desarrollo de la aplicación las cuales son independientes entre si, existe una línea principal y varias paralelas, la principal vendría a ser lo que se conoce como Trunk y las demás serían lo que en SCM se conoce como Branches•Frozen Versions (también conocidas como Labels en SCM), representan los congelados creados en determinados momentos del proceso sobre las DV para determinar ciertos checkpoints (liberación de versión, entrega a cliente, congelar estado, etc.)

Page 414: Aplicaciones Genexus

396

Solución: Manejo de versiones de la aplicación

Nodo raíz del árbol de versiones

APPAPP

Frozen VersionsDevelopment Version

1.0 1.1 1.2 2.0

1.1.1

1.0.1

2.1

1.1.2

1.0.2 1.0.3

Development Version

Manejo de Versiones

Development Version (Trunk)

Se comienza el desarrollo siguiendo una línea principal de desarrollo (línea del medio – Trunk), lugar donde se agregan las funcionalidades requeridas y se utilizan prototipos para probarlas .

En determinados momentos de este ciclo surge la necesidad de establecer un checkpoint en el proceso, ya sea por la liberación de una versión, la entrega de una versión a un cliente, la necesidad de congelar un determinado estado de una aplicación, etc. Entonces lo que hacemos es congelar el producto en ese momento creando por ejemplo la versión 1.0 que se la entregamos a un cliente y se continúa el proceso de desarrollo principal.

En determinado momento surge la necesidad de realizar correcciones sobre la versión entregada al cliente (1.0) por lo que es necesario abrir una nueva línea de desarrollo para incluir estas correcciones sobre lo que era la versión 1.0 sin afectar la línea de desarrollo principal que siguió creciendo desde el momento de la congelación de la versión 1.0.Entonces se crea lo que se conoce como Developmen Version o branch, que es simplemente una nueva línea de desarrollo paralela a la principal.

Luego durante el transcurso del proyecto vuelven a aparecer requerimientos de este tipo, ya sea de determinación de checkpoints como la necesidad de abrir nuevas líneas de desarrollo, entonces por ejemplo creamos la versión 1.1, o la 1.0.1 que vendría a ser un congelado de la línea de desarrollo abierta a partir de la versión 1.0 y así sucesivamente hasta tener por ejemplo la situación planteada en el diagrama.

Estas situaciones forman parte de la operativa normal en el desarrollo de una aplicación y es necesario administrar fácilmente este proceso.

Para ello se introduce el concepto de Manejo de Versiones. Las versiones se clasifican en:

•Development Versions, representan las líneas de desarrollo de la aplicación las cuales son independientes entre si, existe una línea principal y varias paralelas, la principal vendría a ser lo que se conoce como Trunk y las demás serían lo que en SCM se conoce como Branches•Frozen Versions (también conocidas como Labels en SCM), representan los congelados creados en determinados momentos del proceso sobre las DV para determinar ciertos checkpoints (liberación de versión, entrega a cliente, congelar estado, etc.)

Page 415: Aplicaciones Genexus

397

Development Version: (Branch) Línea de desarrollo de la aplicación. Pueden haber varias líneas que transcurran paralelas.

APPAPP

Development Version

1.0 1.1 1.2 2.0

1.1.1

1.0.1

2.1

1.1.2

1.0.2 1.0.3

Development Version

Manejo de Versiones

Development Version principal (Trunk)

Nodo raíz del árbol de versiones = nodo raíz del Trunk

Las development version son las líneas de desarrollo de la aplicación, es decir el lugar donde efectivamente creamos y modificamos la aplicación.

En el ciclo de vida de una aplicación participa una línea de desarrollo principal, es decir, donde comienza el proceso de desarrollo de la aplicación y en la cual normalmente se van a estar haciendo las modificaciones requeridas en el avance del proyecto. En SCM esta línea de desarrollo se conoce con el nombre de Trunk.

Además de esta línea principal podrán existir una o varias líneas de desarrollo secundarias, totalmente independientes de la línea principal e independientes entre si. En SCM estas líneas de desarrollo secundarias se conocen como Branches y son usadas en general para realizar correcciones o pequeños agregados sobre versiones congeladas o liberadas de la aplicación, o para liberar una versión especial para un cliente.

El desarrollo en cada una de estas development version es independiente, teniendo cada versión sus propios objetos, su propia base de datos, ambientes para generar la aplicación, etc.

Una Development Version, es entonces, una copia de la KB editable e independiente.

Page 416: Aplicaciones Genexus

398

Frozen Version: Versión no modificable, es una “foto” de la aplicación en un momento dado. 

Manejo de Versiones

APPAPP

Frozen Versions

1.0 1.1 1.2 2.0

1.1.1

1.0.1

2.1

1.1.2

1.0.2 1.0.3

Una Frozen Version permite almacenar en forma estática momentos especiales de la KB. Es el elemento que utilizamos para marcar distintos hitos en el proceso, como por ejemplo el “cierre” de una versión para liberarla a los clientes.

Se obtiene a partir de una versión en desarrollo (development version), “congelándola” para obtener una “foto” en un determinado momento.

La versión obtenida es Read Only, es decir que objetos de la misma no podrán ser modificados, ni tampoco sus propiedades. Sí será posible realizar acciones relacionadas con la generación de la aplicación, como por ejemplo la creación de la base de datos o la regeneración de los programas.

Cuando congelamos una versión es porque determinamos que la misma está en un estado consistente y sería conveniente guardar dicho estado. Por ejemplo, congelamos una version X para dársela a los clientes, en determinado momento, mientras se continúa con el proceso de desarrollo, un nuevo cliente requiere de la aplicación, entonces lo que hacemos es generar la misma en la version X, que sabemos tiene un estado correcto y se la instalamos al nuevo cliente.

Los objetos si bien no pueden ser modificados, pueden ser abiertos para distintas consultas o para realizar comparaciones con otras versiones de la aplicación.

Page 417: Aplicaciones Genexus

399

Ejemplo de versionado: Implementación paso a paso

APPAPP …..

Variaciones debido a arreglos o cambios en requerimientos

Development Version

“principal”(Trunk)

Ciclo de desarrollo principal - Prototipado

Manejo de Versiones

Partimos del nodo raíz del árbol de versiones, el cual se crea al crear la KB.La aplicación va sufriendo cambios a medida que transcurre el ciclo de desarrollo. La línea de desarrollo principal es donde se implementan las funcionalidades requeridas y donde se hace el prototipado.Esta línea de desarrollo generalmente coincide con el Trunk, o sea con la rama principal del árbol de versionado. Es una Development Version creada por defecto al crearse la KB.A medida que se van haciendo modificaciones a la aplicación, la misma va cambiando a lo largo del tiempo.

Page 418: Aplicaciones Genexus

400

Para ver el árbol de versiones, abrimos la ventana Knowledge Base Versions (View/Versions):

Nodo raíz del árbol de versiones = nodo raíz del Trunk

Manejo de Versiones

Page 419: Aplicaciones Genexus

401

APPAPP ….. Development Version “principal” (Trunk)

1.01.0 Frozen Version 1.0

Manejo de Versiones

Surge la necesidad de “congelar” versiones, para fijar hitos en el proyecto. Para eso creamos Frozen Versions (copia de sólo lectura de la aplicación).

Las Frozen Version sirven para:•Analizar (no modificar) objetos, propiedades, environments, etc. •Como fuente de un Reporte de Análisis de Impacto de la base de datos•Para crear la base de datos •Para regenerar todos los programas

Page 420: Aplicaciones Genexus

402

¿Cómo “congelamos” una Development Version, para crear una Frozen Version?

Damos botón derecho sobre el nodo raíz y seleccionamos Freeze

Manejo de Versiones

Page 421: Aplicaciones Genexus

403

APPAPP ….. Development Version “principal” (Trunk)

1.01.0 1.11.1

Release1Release1DevelopmentVersion para “Producción”

Manejo de Versiones

Ahora queremos poner la aplicación en Producción. Para eso partir de una Frozen Version 1.1 creamos una Development Version“Release 1”.

En la versión de “Producción” se van produciendo variaciones debido a arreglos, pero no se agregafuncionalidades nuevas. Las mismas son agregadas en la línea de desarrollo principal.

Las Development Version sirven para:Trabajar en una línea de desarrollo paralela a la principalComo fuente o destino de una operation de Revert desde una Frozen Version de Backup

Page 422: Aplicaciones Genexus

404

Creamos la Frozen Version 1.1 como vimos anteriormente…

FrozenVersion

1.1Botón derecho sobre el nodo

raíz y click en Freeze

Manejo de Versiones

Nótese que las Frozen Version más nuevas, se muestran más arriba en el árbol de versiones.

Page 423: Aplicaciones Genexus

405

Damos botón derecho sobre la Frozen Version 1.1 y seleccionamos New Version para crear la Development Version Release 1.

DevelopmentVersion

Release1

Manejo de Versiones

El tiempo que se demora en crear una nueva Development Version es proporcional al tamaño de la KB.

Page 424: Aplicaciones Genexus

406

1.1.11.1.1 1.1.21.1.2Frozen Versions de Producción

KB1KB1 ….. Trunk

1.01.0 1.11.1 1.21.2 2.02.0 2.12.1

Release1Release1

Manejo de VersionesTambién podemos crear nuevas Frozen Versions tanto en la rama 

del desarrollo principal como en la rama de  Producción.

Producción

Como las líneas de desarrollo del Trunk (Desarrollo) y de Relase 1 (Producción) son paralelas, los cambios en una no afecta a la otra.

Ambas versiones son entonces totalmente independientes y podemos requerir congelarlas pordiferentes motivos. Por ejemplo, en el caso de la rama de Producción, para fijar un estado luego de ciertos arreglos que tuvimos que hacer.

De acuerdo a la metodología adoptada, en el ciclo de desarrollo principal, es donde se agregan nuevasfuncionalidades, arreglos, cambios importantes a la aplicación, prototipado y testing. Es más frecuenteque se necesita “fotos” en esa etapa viva del desarrollo de la aplicación.

En la rama del Release1, los cambios son menores, más bien arreglos circunstanciales que no agreganfuncionalidad. En este caso, es menos frecuente la necesidad de crear Frozen Versions, pero puede ser igualmente necesario.

Page 425: Aplicaciones Genexus

407

Manejo de VersionesNótese que las Frozen Versions más nuevas, se muestran más 

arriba en el árbol de versiones

Page 426: Aplicaciones Genexus

408

Luego de ciertos arreglos en Producción, nos interesa generar la aplicación. Para eso marcamos la DV Release 1 como activa. 

Damos botón derecho sobre el nodo Release1 y elegimos “Set Active”

Manejo de Versiones

GeneXus genera automáticamente los programas y las estructuras de la BD, partiendo de la versión queesté activa.

Se puede marcar como activa una versión en desarrollo o una versión congelada. En éste último caso, no podremos hacer ninguna modificación a la misma, solamente utilizarla para generar la aplicación o para realizar un impacto a la base de datos, o para comparar versiones.

Solamente puede haber una versión activa a la vez.

Page 427: Aplicaciones Genexus

409

La Development Version que esté activa, será la que se utilizarápara generar la aplicación al hacer un Build (F5)

GeneXus nos indica cuál es la rama activa

Manejo de Versiones

Page 428: Aplicaciones Genexus
Page 429: Aplicaciones Genexus

������� �����

Page 430: Aplicaciones Genexus

���������� ���� ��������������� � ���� ����� ������������� ��� ����������������� ������������ ������������ �� ������ ������������� ������

• !������ ����� ����������

• "� #��������!���������

$��� ��� ������ � ����� �� � �� ���� ����� ���������� ������������ ���� ����� ���� ������� ����!�!� ����!���� ��� �� %&� #� �

���� ���� ���� ���������

Page 431: Aplicaciones Genexus
Page 432: Aplicaciones Genexus

"������'����������"� #� (�� ����� ��� �������� �� �������� ����� #� ��� ��������

)������� *��#����+���������� ����������� � ��� �� ���� ���������� ������

, %-.��/�����, )����

���� ��������������������

Page 433: Aplicaciones Genexus

���'��������� �!"� #� ���� �!� � ��� ����� ��� ����� ������ ���� ��!����� �� � �� ��� � ���� ��/������ ����� #��� %���&��

%&� #� 01)

"��������� 2

, ���'��������

, 3� ��� ����� ����

�����/� ��

)���� ���� � � ���

����� �-������������

��� #� �

������� �������������������

Page 434: Aplicaciones Genexus

4 �#�� ��!�����!��� � ���� ����� ������ �������� ��%&� #� �

��������2

, $�!!��.�"� #�

, 0�����5 �!"� #�

, 6/��78�'9

, "��� ���

����������������������� �!����� ��

Page 435: Aplicaciones Genexus

������

Page 436: Aplicaciones Genexus

$�!!����"� #� ������ ����� ��������� �� � ��������� ����/������ ����� #� �

4� �#� ����������������������� �� ����!����

"����� �� ��� ����!���� �����������������������������!����

���� ��� ���"���������

� � ��������

"�������� �����������#��

4� ���#�� ��� #� ��� ����������������� �� �� �� ��!����

Page 437: Aplicaciones Genexus

$�!!����"� #� ������ ����� ��������� �� � ��������� ����/������ ����� #� �

���� ��� ���"���������

Page 438: Aplicaciones Genexus

����

Page 439: Aplicaciones Genexus

0������ �!"� #� ������ ����� ��� ����� ������� ���� #����� ����� ����� ����!������ �� ���� ������ � ������ ���� � ����/�������

1����� ������!������������������������

:��� � �����#������������

#�������� ��� ���"���������

4� ���������� ��!��;� ��� �������������!��� ���

Page 440: Aplicaciones Genexus

6/��78�'94� !��� #������� ����!!����� �/�� ������������ ������!� ��������������

$%�& '�(��������������������)

Page 441: Aplicaciones Genexus

*������+�����������

Page 442: Aplicaciones Genexus
Page 443: Aplicaciones Genexus

!�������� �"�� ������

(�� ����� �� � ��������� ��� ����������� #� �

8��#�!���� ����� /��������� ����� ������������������������� ������������!��� 5����

Page 444: Aplicaciones Genexus
Page 445: Aplicaciones Genexus

����������

Page 446: Aplicaciones Genexus

� ������

� ��� ������������

Page 447: Aplicaciones Genexus

� ������

25

145

150 300

550

230

10

210

890

320 1090 1100

� � �

1340

905

255

10

� 2510

� 2510

Page 448: Aplicaciones Genexus

����� ���������

Como columna

Page 449: Aplicaciones Genexus

����� ���������

Como página

Page 450: Aplicaciones Genexus

������ ��� ����������

Análogo a un corte de control que corta primero por CountryName, luego por CustomerNamey luego por InvoiceDate, y para los registros de este último grupo, sumarizaInvoiceAmount.

Observación: se busca tabla extendida que contenga CountryName, CustomerName, InvoiceDate e InvoiceAmount.

Page 451: Aplicaciones Genexus

��������������������������

For each order CountryNameDefined by InvoiceDate

print CountryFor each order CustomerName

print CustomerFor each order InvoiceDate

&sum = 0For each

&sum += InvoiceAmountendforPrint DateWithSum

endforendfor

endfor

Pero el usuario no tiene la libertad de cortar la información “pivoteando”(en distinto orden), ni de mostrarla de diferentes formas…

En cambio con un objeto Query…

Conditions: CustomerName in [“Julia”, “Diego”, “Mary”]CountryName = “Uruguay”

Page 452: Aplicaciones Genexus

!����� �"�#���

Page 453: Aplicaciones Genexus

!����� ������������

Page 454: Aplicaciones Genexus

!����� ���������������

Manipulable:

Page 455: Aplicaciones Genexus

� ��� ������������$�������

• �������������� ����� ��������������� �����

• ��� ����������������� ����������� ������

• �� ����������������������� ��������������� ������

• ������������� ��� �������������

Page 456: Aplicaciones Genexus

������������ �����

Prototipación

Page 457: Aplicaciones Genexus

���������� �� ������������

¿Qué puede especificarse dentro del nodo Attributes?

AtributosFunciones de agregaciónExpresiones

Los atributos (simples, agregados o en expresiones) que compongan la consulta que desea realizarse.

Simples (Sum, Count, Average)Condicionadas

Lectura opcional

Page 458: Aplicaciones Genexus

� �������� ������� ���� ����

� ���� ����������� � !���"#���� ��"�� ��� ��������

� ���� ����������� ������ �� $� ��� �����

���������� �� ������������

Sin agregación. Ej: descripciones, fechas, numéricos sin decimales.

Con agregación. Ej: numéricos con decimales,Sum, Count, y Average

Lectura opcional

Page 459: Aplicaciones Genexus

� %� ���������������� ������������ "���"�� ��� �

���������� �� ����

Suma de las ventas del cliente

Cantidad de facturas del cliente

Promedio diario de facturación por cliente

������������ ������������� ���

� �� ���������� �� ��������%�� Average(Count(InvoiceId)

Lectura opcional

Page 460: Aplicaciones Genexus

� ���� ��� �� �� ��� �

���������� �� ����

Los resultados de cualquier función de agregación pueden mostrarse como porcentaje.

������������ ������������� ���

Nota: Se está filtrando por Uruguay, por eso es el 100%

Lectura opcional

Page 461: Aplicaciones Genexus

� ���

� ��� �������

���������� �� ����

Cantidad de clientes por país.

Cantidad de clientes que compraron, por país.

El count avanzado cuenta las ocurrencias distintas del atributo involucrado. Por esta razón colocamos CustomerId y no CustomerName.Estamos pidiendo que cuente los distintos CustomerId que tienen facturas.

������������ ������������� ���

Lectura opcional

Page 462: Aplicaciones Genexus

� �� ���

� �� ��� ���

���������� �� ����

Monto promedio de lo que gasta cada vez que compra

Monto promedio de lo que gasta diariamente

������������ ������������� ���

Lectura opcional

Page 463: Aplicaciones Genexus

���������� �� ���������������� ������������� ��� ���� �������

Se pueden condicionar los datos a consultar.

Pueden definirse filtros de los mismos tipos que los del nodo Filters (general)

Lectura opcional

Page 464: Aplicaciones Genexus

���������� �� ���������������� ������������� ��� ���� �������

Se suman únicamente las facturas (del país) cuyo InvoiceAmount supera los U$S500.

Se muestra el país en la salida, solamente si la suma de los InvoiceAmount de todas sus facturas, supera los U$S 1000.

Se puede realizar el filtro antes o después de la agregación…

Lectura opcional

Page 465: Aplicaciones Genexus

���������� �� ������������������������

� &���� '������

� & �� ����

� #�����������

� !���������

Lectura opcional

Page 466: Aplicaciones Genexus

���������� �� ���������������������

Rango con valores constantes

Lista de valores constantes

Operador Like Rango o Lista de valores no constantes (subconsulta)

Lectura opcional

Page 467: Aplicaciones Genexus

���������� �� ����������������

� (�)������ ��� * ����� ��� ���� ��'������+����������������&�+, ��

Sus elementos se unen con OR

Sus elementos se unen con OR

Luego se aplica el AND

Lectura opcional

Page 468: Aplicaciones Genexus

���������� �� ����������

� -���������������������������������� ������

Lectura opcional

Page 469: Aplicaciones Genexus

���������� �!����� �����������

Ejemplo: Se resuelve con 2 consultas select de las que luego se hace full join:

Tabla base: Invoice

Tabla base: Bill

Lectura opcional

Page 470: Aplicaciones Genexus

��������%����������������%�

�!�"#��� ��#$ � $�!

Page 471: Aplicaciones Genexus

����&��'�

Page 472: Aplicaciones Genexus

� ��� ���������� ������������.�+�������� �

����&��'�

Page 473: Aplicaciones Genexus

� ���������-/�+������� ������������ ������ ��������&��'�

{PivotTable, Table, Chart, Default}

{DataProvider, Query}

{Row, Column, Page, Data, NotShow}

{Ascending, Descending, Custom}

Page 474: Aplicaciones Genexus

� ��� ���������� ������������.�+�������� �

����&��'�

Page 475: Aplicaciones Genexus

����&��'�

• �����/����

• /���� ����

• 0�������

������

Page 476: Aplicaciones Genexus
Page 477: Aplicaciones Genexus

Desarrollo de Aplicaciones con tecnología GeneXus Curso 2013

Práctico 1 – Diseño de Transacciones

Se quiere implementar un sistema para administrar el funcionamiento de un Cambio.

Se busca registrar la cotización de las monedas respecto al Peso Uruguayo. De la moneda se

conoce su descripción, su símbolo y el histórico de cotizaciones incluyendo compra y venta. El

histórico busca registrar un valor de cotización y la fecha desde la que tiene vigencia.

1) Diseñar la transacción Moneda teniendo en cuenta además que:

- El símbolo se debe ingresar obligatoriamente

La pizarra electrónica que se coloca en la entrada del cambio toma el valor desde nuestro

sistema. Cada pizarra se identifica por la fecha en la que se presenta, también muestra la

fecha en texto (p.e 23 de Abril de 2013). Luego en forma de renglón muestra una moneda y la

cotización vigente para la fecha de la pizarra.

2) Diseñar la transacción pizarra teniendo en cuanta además que:

- Al ingresar una nueva pizarra debe sugerir como fecha, la fecha de hoy

Las boletas de cambio registran una operación hecha en alguna sucursal. De la boleta se

conoce la fecha, la sucursal, el tipo de operación (COMPRA o VENTA), la moneda, la cotización

vigente a la fecha de hoy, el importe de la operación y el importe resultado de la operación. De

las sucursales se conoce su dirección, el teléfono y la cantidad de operaciones realizadas.

3) Diseñar la transacción Sucursal y Boleta teniendo en cuenta que:

- Al ingresar una boleta, las sucursales deben salir listadas en un combo box para

que el usuario del sistema pueda seleccionarla.

- Crear un dominio para los tipos que representan importes

Verificar como GeneXus respeta la integridad referencial

Forma de entrega

El trabajo debe realizarse en forma individual y la entrega consiste en un archivo xpz de

nombre <Cedula>_<NombreApellido>.xpz con la resolución de los ejercicios.

El xpz debe enviarse a la casilla [email protected] antes del día 30 de Abril

(inclusive).

Page 478: Aplicaciones Genexus
Page 479: Aplicaciones Genexus

Desarrollo de Aplicaciones con tecnología GeneXus Curso 2011

Página 1

Laboratorio Desarrollo de aplicaciones GeneXus 2011 Una empresa multinacional de alquiler de autos decide ofrecer sus servicios de renta y consultas a través de un sistema Web. Se busca que cualquier cliente registrado pueda consultar la flota de automóviles que ofrece la empresa, y de quererlo realizar la reserva del coche. Entonces se quiere un sistema que requiera autenticación, en caso de que el cliente no esté registrado se le dará la opción de hacerlo. Si el usuario no se autentica entonces no podrá acceder a ninguna funcionalidad del sistema y este lo redirigirá automáticamente a la pantalla de login. Clientes: Al registrarse, el usuario deberá elegir un Nick el cual debe ser único. Deberá empezar con una letra, no podrá contener espacios y solo puede estar formado por letras, números y guión bajo. Además deberá ingresar obligatoriamente nombres, apellidos, país, ciudad, dirección e email de contacto. También ingresa la contraseña y una casilla extra para repetir la contraseña así se puede verificar que fue escrita correctamente. Al ingresar el País mediante un ComboBox automáticamente se muestran solo las ciudades de ese país en el comboBox de ciudades. Luego de realizado el login se muestra una pantalla en la que se muestra algún promoción de la empresa. La promoción consta de algún modelo de la flota y una descripción de Marketing. En todo momento debe visualizarse el usuario conectado y el rol (por ejemplo en la Master Page). Vehículos: Los vehículos serán rentados por la empresa a los clientes. Se cuenta con varios vehículos de cada modelo. Cada Modelo está identificado por la marca y el nombre del modelo (p.e Ford, Escort). Deberá existir una pantalla para administrar las marcas. De cada modelo se conoce una foto, una descripción breve del modelo, cilindrada, tipo de motor (gasoil o nafta), el costo de alquiler por día, si tiene dirección hidráulica, si tiene aire acondicionado y capacidad. También se desea visualizar la cantidad de vehículos en la flota que son de ese modelo, Un vehículo está identificado por la matrícula y se conoce su modelo. Además es necesario registrar la cantidad de kilómetros que tiene, color, si está en renta o no, y si está en el taller o no. Renta: Cuando un cliente desea rentar un auto realiza una búsqueda de modelos de autos. Debe poder realizar búsquedas pudiendo filtrar por al menos marca, modelo, capacidad y precio. De los modelos que cumplan las condiciones de búsqueda se debe mostrar foto del modelo, nombre del modelo, marca, una descripción breve del modelo, cilindrada, tipo de motor (gasoil o nafta), el costo de alquiler por día, si tiene

Page 480: Aplicaciones Genexus

Desarrollo de Aplicaciones con tecnología GeneXus Curso 2011

Página 2

dirección hidráulica, si tiene aire acondicionado y capacidad. Para esto utilizar una Free Style grid. Junto a cada modelo debe aparecer la opción de rentar. Al seleccionar la opción se redirige a una pantalla en la cual se muestran otra vez los datos del modelo seleccionado y se pide al usuario que ingrese la fecha desde la cual quiere alquilar y la cantidad de días. A través de un botón se muestra una grilla con los vehículos disponibles del modelo seleccionado y el costo total de la renta. El usuario elige un vehículo y se emite un listado pdf que funciona como comprobante en el que se muestra los datos del cliente, la fecha de la reserva, la cantidad de días, el total a pagar y los datos del vehículo. Al momento de confirmar se ingresa la reserva del vehículo. Una reserva está identificada por el vehículo, y la fecha de la reserva (no es posible reservar un vehículo más de una vez en un día). La reserva tiene además la cantidad de días que se alquiló, el kilometraje que se hizo durante el alquiler, el cliente que hizo la reserva y el estado (abierta, cerrada). Al ingresar la reserva, esta queda abierta Luego, cuando el cliente retorna con el vehículo un usuario administrador ingresa los kilómetros realizados y marca la reserva como cerrada.

Objetivo: Implementar la seguridad requerida para los clientes. Esto incluye mostrar solo las opciones de menú que corresponden. Implementar para el cliente las funcionalidades de:

- Buscar Modelo - Rentar auto - Ver las reservas realizadas.

Implementar para el administrador las funcionalidades de:

- Reporte de estado de vehículos (permitir filtros por modelo) - Ver reservas pendientes - Reporte de historial de reservas de un vehículo. - Reporte de reservas por rango de fechas. Agrupar por fecha los totales de

las reservas de cada modelo (solo los modelos que efectivamente tuvieron reservas en el rango de fecha)

Consideraciones: 1) Instalar el User control MultiLevelMenu que viene en el archivo MultiLevelMenu.zip: http://wiki.gxtechnical.com/commwiki/servlet/hwiki?Default+Installation+Instructions+for+User+Controls,

Page 481: Aplicaciones Genexus

Desarrollo de Aplicaciones con tecnología GeneXus Curso 2011

Página 3

2) Luego, y solo luego de instalar el user control, cargar el XPZ laboratorioGX2011.xpz que contiene la masterPage y el tema a utilizar para el laboratorio. Deberá modificarse el data provider dataProviderMLM para cargar las opciones del menú de la aplicación y establecer como MasterPage y tema por defecto los del XPZ (el tema es K2b3).

3) Para el manejo de la seguridad utilizar el tipo de dato WebSession. Este tipo de dato permite almacenar pares {etiqueta, valor} a lo largo de la sesión del usuario. Por ejemplo para la seguridad se puede utilizar la etiqueta ‘userid’ para mantener el id del usuario, entonces al momento de hacer el login guardamos este valor utilizando el método set del tipo de dato webSession: &Session.set(‘userid’, <NombreDeUsuario>)

Luego en el evento Start de la masterPage verificamos que este valor exista de lo contrario redirigimos al usuario a, por ejemplo, la pantalla de login: &Usuario = &Session.get(‘userid’)

If &usuario.isEmpty()

Login.call()

http://wiki.gxtechnical.com/commwiki/servlet/hwiki?WebSession,

Inscripción: El laboratorio se realizará en grupos de hasta 3 personas. Enviar correo a [email protected] con los nombres de los integrantes antes del 30 de octubre.

Page 482: Aplicaciones Genexus

Desarrollo de Aplicaciones con tecnología GeneXus Curso 2011

Página 4

Fechas de entrega y evaluación:

Enviar a [email protected] un archivo comprimido de nombre labGXGr_XX.zip (donde XX es el número de grupo), conteniendo un XPZ de nombre labGXGrXX.XPZ con la solución del laboratorio y un documento de nombre labGXGrXX.doc con una descripción breve de la solución implementada. No está permitido intercambiar objetos GeneXus entre los grupos y aquellos casos en los que se detecten objetos copiados serán pasibles de sanciones. La entrega debe realizarse hasta las 23:59 del día 23 de noviembre.

Referencias: Search de GeneXus: http://www.gxtechnical.com/gxsearch Wiki de GeneXus: http://www.gxtechnical.com/wiki/ Grupo google del curso: http://groups.google.com.uy/group/desarrollo-de-aplicaciones-con-genexus-tecnologo/

Page 483: Aplicaciones Genexus
Page 484: Aplicaciones Genexus

Práctico 1 – Diseño de transacciones – Curso Desarrollo de aplicaciones basadas en tecnología GeneXus

Ejercicio 1

Se desea modelar un sistema para la administración de las salas de la emergencia de un hospital. Al

ingresar un paciente a la emergencia se lo registra en el sistema. Cada paciente es identificado por el

‘número de paciente’ el cual es asignado en forma automática por el sistema. También se ingresan los

dos nombres y los dos apellidos (debiendo ingresar en forma obligatoria primer nombre y primer

apellido), cédula de identidad (única para cada paciente) y fecha de nacimiento. El sistema registra la

fecha en la que se ingresó al paciente y la fecha en que utilizó por última vez a la emergencia.

Lugo el paciente describe los síntomas que presenta y el usuario del sistema ingresa la descripción en los

datos del paciente. Únicamente se podrá ingresar una descripción por día para cada cliente. De esta

forma al momento de consultar los datos del paciente se verán las distintas visitas a la emergencia.

Finalmente hay que asignar al paciente una cama del hospital. Cada cama será parte de una sala. Las

salas están identificadas por una letra, se conoce la ubicación dentro del Hospital (SUR, NORTE, ESTE,

OESTE), la cantidad total de camas, la cantidad de camas libres, fecha del último mantenimiento. Luego

se ven las camas, cada una identificada por un número único dentro de la sala. Se registra también la

fecha en la que fue ingresada en la sala, el estado, que puede ser OCUPADA o LIBRE. En caso de estar

ocupada se conoce también el paciente (y la descripción de los síntomas) asignado a la cama.

Entonces, al ingresar un paciente, se toman los datos personales y de los síntomas presentados, se pasa

a la pantalla de mantenimiento de Salas y camas y se asigna una cama al paciente para que sea tratado

por los síntomas descriptos en el ingreso.

Crear un modelo Web en GeneXus

Realizar el diseño de las transacciones para el problema descripto, incluyendo las reglas,

formulas y eventos que considere necesarios.

Ejecutar la aplicación con las reorganizaciones necesarias y verificar que el comportamiento es

el deseado.

Forma de entrega

El trabajo debe realizarse en forma individual y la entrega consiste en un archivo xpz de nombre

<Cedula>_<NombreApellido>.xpz con la resolución del ejercicio 1.

El xpz debe enviarse a la casilla [email protected] antes del día 15 de setiembre

(inclusive).

Page 485: Aplicaciones Genexus
Page 486: Aplicaciones Genexus

1) 10 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles

Se ensamblan distintas marcas de autos (marca). Un Auto tiene una Marca. A su vez pueden haber muchos

autos de una marca

Determine el diseño de transacciones que considere correcto para representar dicha realidad.

2) 10 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles

Un Auto está compuesto por varios tipos de Piezas (PiezaTipo). Un tipo de pieza puede ser parte de muchos

autos.

Determine el diseño de transacciones que considere correcto para representar dicha realidad.

Marca { MarcaId* MarcaDescripcion Auto { AutoId* AutoDescripcion } }

Auto { AutoId * AutoDescripcion MarcaId MarcaDescripcion }

Marca { MarcaId * MarcaDescripcion }

Auto { AutoId * AutoDescripcion }

Marca { MarcaId * MarcaDescripcion AutoId AutoDescripcion }

a)

b)

c)

d) Ninguna de las anteriores

a) Auto { AutoId * AutoDescripcion PiezaTipoId PiezaTipoDesc }

PiezaTipo { PiezaTipoId * PiezaTipoDesc }

Auto { AutoId* AutoDescripcion PiezaTipo { PiezaTipoId* PiezaTipoDesc } }

c) d) Ninguna de las anteriores

b)

PiezaTipo { PiezaTipoId * PiezaTipoDesc }

Auto { AutoId * AutoDescripcion }

PiezaTipo { PiezaTipoId * AutoId* PiezaTipoDesc }

1

Page 487: Aplicaciones Genexus

3) 10 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles

Un Auto está compuesto por varias Piezas (Pieza). Estás piezas son utilizadas únicamente para esos Autos por lo

que no puede haber una Pieza que no esté asociada a un Auto.

Determine el diseño de transacciones que considere correcto para representar dicha realidad.

4) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

A partir del siguiente diseño de transacciones, determine la estructura física de las tablas que GeneXus creará.

b)

d)

a) Auto { AutoId * AutoDescripcion PiezaId PiezaNombre }

Pieza { PiezaId * PiezaNombre }

Auto { AutoId* AutoDescripcion Pieza { PiezaId* PiezaNombre } }

Pieza { PiezaId * PiezaNombre }

c) Auto { AutoId* AutoDescripcion Pieza { PiezaId* PiezaNombre } }

Pieza { PiezaId * PiezaNombre Auto { AutoId * AutoDescripcion } }

Auto { AutoId * AutoDescripcion }

Automotora { AutomotoraId* AutomotoraNom }

Auto { AutoId * AutoDescripcion AutoPrecio }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom Fx EnvioTotal Auto { AutoId * AutoDescripcion AutoPrecio } }

Sum(AutoPrecio)

Automotora AutomotoraId * AutomotoraNom

Auto AutoId * AutoDescripcion AutoPrecio

Envio EnvioId * EnvioFecha EnvioTotal

EnvioAuto EnvioId * AutoId * AutoDescripcion AutoPrecio

a)

1

Page 488: Aplicaciones Genexus

5) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

Dado el siguiente diseño de transacciones, determine la tabla extendida de la tabla Envío.

6) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

Dado el siguiente diagrama de Bachman, determine la tabla extendida de EnvioAuto.

Automotora AutomotoraId * AutomotoraNom

Auto AutoId * AutoDescripcion AutoPrecio

Envio EnvioId * EnvioFecha AutomotoraId

EnvioAuto EnvioId * AutoId *

Automotora AutomotoraId * AutomotoraNom

Auto AutoId * AutoDescripcion AutoPrecio

Envio EnvioId * EnvioFecha AutomotoraId AutomotoraNom

EnvioAuto EnvioId * AutoId *

d) Ninguna de las anteriores

Automotora { AutomotoraId* AutomotoraNom }

Auto { AutoId * AutoDescripcion AutoPrecio }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

a) No posee tabla extendida

b) {Envío, EnvioAuto}

c) {Envío, Automotora}

d) {Envío, Automotora, EnvioAuto,Auto }

Envío

EnvioAuto

Automotora

Auto

a) No posee tabla extendida

b) {Envío, EnvioAuto}

c) {Envío, Automotora}

d) {Envío, Automotora, EnvioAuto,Auto }

b)

c)

1

Page 489: Aplicaciones Genexus

7) 2 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Auto para registrar los automóviles que son ensamblados. De los autos es

necesario registrar el país de origen del constructor y el país de origen de los repuestos.

Determine el diseño de transacciones que considere correcto.

8) 4 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

Dado el siguiente diseño de transacciones. Suponga que existe un único País ingresado en la base con PaisId = 4.

Indique que sucede si se intenta ingresar una nueva Marca con PaisId = 9.

Auto { AutoId* AutoDescripcion ContructorPaisId ContructorPaisNombre RepuestoPaisId RepuestoPaisNombre }

Pais { PaisId* PaisNombre }

Subtype group: ConstructorPaisId ContructorPaisId subtype or PaisId Subtype group: ConstructorPaisNombre ContructorPaisNombre subtype of PaisNombre Subtype group: RepuestoPaisId RepuestoPaisId subtype or PaisId Subtype group: RepuestoPaisNombre RepuestoPaisNombre subtype of PaisNombre

Auto { AutoId* AutoDescripcion ContructorPaisId ContructorPaisNombre RepuestoPaisId RepuestoPaisNombre }

Pais { PaisId* PaisNombre }

Subtype group: ConstructorPais ContructorPaisId subtype or PaisId ContructorPaisNombre subtype of PaisNombre Subtype group: RepuestoPais RepuestoPaisId subtype or PaisId RepuestoPaisNombre subtype of PaisNombre

Auto { AutoId* AutoDescripcion PaisId PaisNombre RepuestoPaisId RepuestoPaisNombre }

Pais { PaisId* PaisNombre }

d) Ninguna de las anteriores

Marca { MarcaId * MarcaDescripcion PaisId PaisNombre }

Pais { PaisId * PaisNombre }

a) Se ingresa la nueva marca y

automáticamente crea el país 9 con Nombre

de país vacío.

b) GeneXus verifica que exista el país 9 en la

tabla País. Como no existe emite un

mensaje de error y no se ingresa la nueva

marca.

c) Se ingresa la nueva marca sin un país

asociado.

d) Ninguna de las anteriores

a)

b)

c)

1

Page 490: Aplicaciones Genexus

9) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. La hora del

envío (EnvíoHora) debe asignarse en el momento exacto en el que se ingresa el envío. Se declara entonces la

siguiente regla en la transacción Envío, determine la opción correcta:

EnvioHora = now() if insert on BeforeComplete

10) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. Se quiere

que al trabajar con cada línea del detalle del envío (EnvioAuto), ya sea alta, baja o modificación, se ejecute el

procedimiento logEnvio que recibe como parámetro el identificador del envío.

Envio { EnvioId* EnvioFecha EnvioHora AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

a) La regla está bien declarada porque al ejecutarse antes del

COMMIT y solo en modo INSERT la hora se guarda con el valor

deseado.

b) La regla está mal declarada porque si bien se ejecuta antes de

COMMIT el registro del cabezal ya fue grabado en la base de

datos.

c) La regla está mal declarada porque se ejecuta una vez para cada

registro del segundo nivel.

d) Ninguna de las anteriores.

Envio { EnvioId* EnvioFecha EnvioHora AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

a) logEnvio.call(EnvioId) ;

b) logEnvio.call(EnvioId) on AfterComplete;

c) logEnvio.call(EnvioId) on AfterValidate;

.

d) logEnvio.call(EnvioId) on AfterValidate level AutoId;

1

Page 491: Aplicaciones Genexus

11) 7 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. Se necesita

emitir un listado de los envíos por automotora. Se listaran solo aquellas automotoras para lasque hayan envíos.

Determine cual es la implementación correcta.

12) 7 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. Dado el

siguiente diseño de transacciones determine las tablas bases de los for each que aparecen a continuación.

Automotora { AutomotoraId* AutomotoraNom }

Auto { AutoId * AutoDescripcion AutoPrecio }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

For each

Print --- (AutomotoraId, AutomotoraNom)

For each

Print --- (EnvioId, EnvioFecha)

Endfor Endfor

For each order AutomotoraId

Print --- (AutomotoraId, AutomotoraNom)

For each

Print --- (EnvioId, EnvioFecha)

Endfor Endfor

For each order AutomotoraId Defined by EnvioFecha

Print --- (AutomotoraId, AutomotoraNom)

For each

Print --- (EnvioId, EnvioFecha)

Endfor Endfor

For each

Print --- (AutomotoraId, AutomotoraNom)

For each AutomotoraId

Print --- (EnvioId, EnvioFecha)

Endfor Endfor

a)

b)

c) d)

Automotora { AutomotoraId* AutomotoraNom }

Auto { AutoId * AutoDescripcion AutoPrecio }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

For each

Print --- (EnvioId, EnvioFecha) For each

Print --- (AutoId, AutoDescripcion)

Endfor Endfor

a) For each Externo {ENVIO}, for each interno {ENVIOAUTO}

b) For each Externo {ENVIO}, for each interno {AUTO}

c) For each Externo {ENVIOAUTO}, for each interno {ENVIOAUTO}

d) For each Externo {ENVIO }, for each interno {ENVIO}

1

Page 492: Aplicaciones Genexus

13) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. Dado el

siguiente diseño de transacciones determine qué tipo de for each es el siguiente:

14) 3 pts. Determine cuál de las siguientes afirmaciones sobre Data Providers es correcta.

15) 3 pts. Determine cuál de las siguientes afirmaciones sobre Business component (BC) es correcta

16) 6 pts. Se tiene un Web Panel SIN TABLA BASE con una grilla para listar todos los Autos que existen en el sistema. Si se sabe que en la tabla autos existen 50 autos ingresados. ¿Cuántas veces se ejecuta el evento load de la grilla?

Automotora { AutomotoraId* AutomotoraNom }

Auto { AutoId * AutoDescripcion AutoPrecio }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

For each

Print --- (EnvioId, EnvioFecha) For each

Print --- (AutomotoraId, AutomotoraNom)

Endfor Endfor

a) JOIN

b) Producto cartesiano

c) Corte de control

d) Ninguna de las anteriores

a) El Data Provider es un objeto que me permite procesar datos para obtener información en forma

estructurada (SDTs, bussines component, ext.).

b) El Data Provider es un objeto utilizado para actualizar la base de datos.

c) Ninguna de las anteriores es correcta.

a) Un objeto BC permite invocar una transacción desde código GeneXus como si esta estuviese

siendo ejecutada desde su Web Form.

b) A través de un BC se puede actualizar la base de datos desde un Web Panel

c) Al llamar un BC, este no hace COMMIT sobre la base de datos y queda a cargo del programador

la confirmación de los datos en la base de datos.

d) Todas las anteriores son correctas.

a) 1 vez

b) 50 veces

c) Ninguna vez

d) 10 Veces

1

Page 493: Aplicaciones Genexus

17) 8 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles. La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. La transacción Automotora, que se utiliza para mantener las automotoras a las cuales la ensambladora realiza los envíos, tiene el atributo AutomotoraEsPref para identificar aquellas que son clientes preferenciales de la ensambladora. Se quiere construir un Web Panel que liste todos los envíos del sistema mostrando en una columna el texto ‘PREFERENCIAL’ para aquellos envíos a automotoras que son clientes preferenciales y el texto ‘CLIENTE COMUN’ para aquellas que no. Determine la opción de implementación que considere correcta.

Automotora { AutomotoraId * AutomotoraNom AutomotoraEsPref }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom AutomotoraEsPref }

a)

b)

d) Ninguna de las anteriores

c)

1

Page 494: Aplicaciones Genexus
Page 495: Aplicaciones Genexus

1) 2 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Auto para registrar los automóviles que son ensamblados. De los autos es

necesario registrar el país de origen del constructor y el país de origen de los repuestos.

Determine el diseño de transacciones que considere correcto.

2) 4 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

Dado el siguiente diseño de transacciones. Suponga que existe un único País ingresado en la base con PaisId = 4.

Indique que sucede si se intenta ingresar una nueva Marca con PaisId = 9.

Auto { AutoId* AutoDescripcion ContructorPaisId ContructorPaisNombre RepuestoPaisId RepuestoPaisNombre }

Pais { PaisId* PaisNombre }

Subtype group: ConstructorPaisId ContructorPaisId subtype or PaisId Subtype group: ConstructorPaisNombre ContructorPaisNombre subtype of PaisNombre Subtype group: RepuestoPaisId RepuestoPaisId subtype or PaisId Subtype group: RepuestoPaisNombre RepuestoPaisNombre subtype of PaisNombre

Auto { AutoId* AutoDescripcion ContructorPaisId ContructorPaisNombre RepuestoPaisId RepuestoPaisNombre }

Pais { PaisId* PaisNombre }

Subtype group: ConstructorPais ContructorPaisId subtype or PaisId ContructorPaisNombre subtype of PaisNombre Subtype group: RepuestoPais RepuestoPaisId subtype or PaisId RepuestoPaisNombre subtype of PaisNombre

d) Ninguna de las anteriores

Marca { MarcaId * MarcaDescripcion PaisId PaisNombre }

Pais { PaisId * PaisNombre }

a) GeneXus verifica que exista el país 9 en la

tabla País. Como no existe emite un

mensaje de error y no se ingresa la nueva

marca.

b) Se ingresa la nueva marca sin un país

asociado.

c) Se ingresa la nueva marca y

automáticamente crea el país 9 con Nombre

de país vacío.

d) Ninguna de las anteriores

a)

b)

c)

2

Auto { AutoId* AutoDescripcion PaisId PaisNombre RepuestoPaisId RepuestoPaisNombre }

Pais { PaisId* PaisNombre }

Page 496: Aplicaciones Genexus

3) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. La hora del

envío (EnvíoHora) debe asignarse en el momento exacto en el que se ingresa el envío. Se declara entonces la

siguiente regla en la transacción Envío, determine la opción correcta:

EnvioHora = now() if insert on BeforeComplete

4) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. Se quiere

que al trabajar con cada línea del detalle del envío (EnvioAuto), ya sea alta, baja o modificación, se ejecute el

procedimiento logEnvio que recibe como parámetro el identificador del envío.

Envio { EnvioId* EnvioFecha EnvioHora AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

a) La regla está bien declarada porque al ejecutarse antes del

COMMIT y solo en modo INSERT la hora se guarda con el valor

deseado.

b) La regla está mal declarada porque se ejecuta una vez para cada

registro del segundo nivel.

c) La regla está mal declarada porque si bien se ejecuta antes de

COMMIT el registro del cabezal ya fue grabado en la base de

datos.

d) Ninguna de las anteriores.

Envio { EnvioId* EnvioFecha EnvioHora AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

a) logEnvio.call(EnvioId) ;

b) logEnvio.call(EnvioId) on AfterValidate;

c) logEnvio.call(EnvioId) on AfterComplete;

d) logEnvio.call(EnvioId) on AfterValidate level AutoId;

2

Page 497: Aplicaciones Genexus

5) 7 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. Se necesita

emitir un listado de los envíos por automotora. Se listaran solo aquellas automotoras para lasque hayan envíos.

Determine cual es la implementación correcta.

6) 7 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. Dado el

siguiente diseño de transacciones determine las tablas bases de los for each que aparecen a continuación.

Automotora { AutomotoraId* AutomotoraNom }

Auto { AutoId * AutoDescripcion AutoPrecio }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

For each

Print --- (AutomotoraId, AutomotoraNom)

For each

Print --- (EnvioId, EnvioFecha)

Endfor Endfor

For each order AutomotoraId

Print --- (AutomotoraId, AutomotoraNom)

For each

Print --- (EnvioId, EnvioFecha)

Endfor Endfor

For each order AutomotoraId Defined by EnvioFecha

Print --- (AutomotoraId, AutomotoraNom)

For each

Print --- (EnvioId, EnvioFecha)

Endfor Endfor

For each

Print --- (AutomotoraId, AutomotoraNom)

For each AutomotoraId

Print --- (EnvioId, EnvioFecha)

Endfor Endfor

a)

b)

c) d)

Automotora { AutomotoraId* AutomotoraNom }

Auto { AutoId * AutoDescripcion AutoPrecio }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

For each

Print --- (EnvioId, EnvioFecha) For each

Print --- (AutoId, AutoDescripcion)

Endfor Endfor

a) For each Externo {ENVIO}, for each interno {AUTO}

b) For each Externo {ENVIO}, for each interno {ENVIOAUTO}

c) For each Externo {ENVIO}, for each interno {ENVIO}

d) For each Externo {ENVIOAUTO }, for each interno {ENVIOAUTO}

2

Page 498: Aplicaciones Genexus

7) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. Dado el

siguiente diseño de transacciones determine qué tipo de for each es el siguiente:

8) 3 pts. Determine cuál de las siguientes afirmaciones sobre Data Providers es correcta.

9) 3 pts. Determine cuál de las siguientes afirmaciones sobre Business component (BC) es correcta

10) 6 pts. Se tiene un Web Panel SIN TABLA BASE con una grilla para listar todos los Autos que existen en el sistema. Si se sabe que en la tabla autos existen 50 autos ingresados. ¿Cuántas veces se ejecuta el evento load de la grilla?

Automotora { AutomotoraId* AutomotoraNom }

Auto { AutoId * AutoDescripcion AutoPrecio }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

For each

Print --- (EnvioId, EnvioFecha) For each

Print --- (AutomotoraId, AutomotoraNom)

Endfor Endfor

a) Producto cartesiano

b) Corte de control

c) JOIN

d) Ninguna de las anteriores

a) El Data Provider es un objeto que me permite procesar datos para obtener información en forma

estructurada (SDTs, bussines component, ext.).

b) El Data Provider es un objeto utilizado para actualizar la base de datos.

c) Ninguna de las anteriores es correcta.

a) Un objeto BC permite invocar una transacción desde código GeneXus como si esta estuviese

siendo ejecutada desde su Web Form.

b) A través de un BC se puede actualizar la base de datos desde un Web Panel

c) Al llamar un BC, este no hace COMMIT sobre la base de datos y queda a cargo del programador

la confirmación de los datos en la base de datos.

d) Todas las anteriores son correctas.

a) 1 vez

b) 10 Veces

c) 50 veces

d) Ninguna vez

2

Page 499: Aplicaciones Genexus

11) 8 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles. La misma cuenta con la transacción Envío para registrar los envíos despachados a las automotoras. La transacción Automotora, que se utiliza para mantener las automotoras a las cuales la ensambladora realiza los envíos, tiene el atributo AutomotoraEsPref para identificar aquellas que son clientes preferenciales de la ensambladora. Se quiere construir un Web Panel que liste todos los envíos del sistema mostrando en una columna el texto ‘PREFERENCIAL’ para aquellos envíos a automotoras que son clientes preferenciales y el texto ‘CLIENTE COMUN’ para aquellas que no. Determine la opción de implementación que considere correcta.

Automotora { AutomotoraId * AutomotoraNom AutomotoraEsPref }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom AutomotoraEsPref }

a)

b)

d) Ninguna de las anteriores

c)

2

Page 500: Aplicaciones Genexus

12) 10 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles

Se ensamblan distintas marcas de autos (marca). Un Auto tiene una Marca. A su vez pueden haber muchos

autos de una marca

Determine el diseño de transacciones que considere correcto para representar dicha realidad.

13) 10 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles

Un Auto está compuesto por varios tipos de Piezas (PiezaTipo). Un tipo de pieza puede ser parte de muchos

autos.

Determine el diseño de transacciones que considere correcto para representar dicha realidad.

Marca { MarcaId* MarcaDescripcion Auto { AutoId* AutoDescripcion } }

Auto { AutoId * AutoDescripcion MarcaId MarcaDescripcion }

Marca { MarcaId * MarcaDescripcion }

Auto { AutoId * AutoDescripcion }

Marca { MarcaId * MarcaDescripcion AutoId AutoDescripcion }

a)

b)

c)

d) Ninguna de las anteriores

a)

Auto { AutoId * AutoDescripcion PiezaTipoId PiezaTipoDesc }

PiezaTipo { PiezaTipoId * PiezaTipoDesc }

Auto { AutoId* AutoDescripcion PiezaTipo { PiezaTipoId* PiezaTipoDesc } }

c) d) Ninguna de las anteriores

b)

PiezaTipo { PiezaTipoId * PiezaTipoDesc }

Auto { AutoId * AutoDescripcion }

PiezaTipo { PiezaTipoId * AutoId* PiezaTipoDesc }

2

Page 501: Aplicaciones Genexus

14) 10 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles

Un Auto está compuesto por varias Piezas (Pieza). Estás piezas son utilizadas únicamente para esos Autos por lo

que no puede haber una Pieza que no esté asociada a un Auto.

Determine el diseño de transacciones que considere correcto para representar dicha realidad.

15) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

A partir del siguiente diseño de transacciones, determine la estructura física de las tablas que GeneXus creará.

b)

d)

a) Auto { AutoId * AutoDescripcion PiezaId PiezaNombre }

Pieza { PiezaId * PiezaNombre }

Auto { AutoId* AutoDescripcion Pieza { PiezaId* PiezaNombre } }

Pieza { PiezaId * PiezaNombre }

c)

Auto { AutoId* AutoDescripcion Pieza { PiezaId* PiezaNombre } }

Pieza { PiezaId * PiezaNombre Auto { AutoId * AutoDescripcion } }

Auto { AutoId * AutoDescripcion }

Automotora { AutomotoraId* AutomotoraNom }

Auto { AutoId * AutoDescripcion AutoPrecio }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom Fx EnvioTotal Auto { AutoId * AutoDescripcion AutoPrecio } }

Sum(AutoPrecio)

Automotora AutomotoraId * AutomotoraNom

Auto AutoId * AutoDescripcion AutoPrecio

Envio EnvioId * EnvioFecha EnvioTotal

EnvioAuto EnvioId * AutoId * AutoDescripcion AutoPrecio

a)

2

Page 502: Aplicaciones Genexus

16) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

Dado el siguiente diseño de transacciones, determine la tabla extendida de la tabla Envío.

17) 5 pts. Se tiene una aplicación GeneXus para una ensambladora de Automóviles.

Dado el siguiente diagrama de Bachman, determine la tabla extendida de EnvioAuto.

Automotora AutomotoraId * AutomotoraNom

Auto AutoId * AutoDescripcion AutoPrecio

Envio EnvioId * EnvioFecha AutomotoraId

EnvioAuto EnvioId * AutoId *

Automotora AutomotoraId * AutomotoraNom

Auto AutoId * AutoDescripcion AutoPrecio

Envio EnvioId * EnvioFecha AutomotoraId AutomotoraNom

EnvioAuto EnvioId * AutoId *

d) Ninguna de las anteriores

Automotora { AutomotoraId* AutomotoraNom }

Auto { AutoId * AutoDescripcion AutoPrecio }

Envio { EnvioId* EnvioFecha AutomotoraId AutomotoraNom Auto { AutoId * AutoDescripcion AutoPrecio } }

a) No posee tabla extendida

b) {Envío, EnvioAuto}

c) { Envío, Automotora, EnvioAuto,Auto }

d) { Envío, Automotora}

Envío

EnvioAuto

Automotora

Auto

a) No posee tabla extendida

b) { Envío, Automotora, EnvioAuto,Auto }

c) {Envío, Automotora}

d) { Envío, EnvioAuto}

b)

c)

2