Saltar al contenido principal
Version: Next (5.0)

Definición de maintain

El motor de maintain se usa para realizar operaciones que no devuelven datos. Estas operaciones sirven para actualizar datos en el servidor. Solo devuelven el resultado del proceso: si la operación ha ido bien o si ha habido un problema al realizarla.

tip

Cada elemento y atributo de los targets de maintain está listado en la referencia XSD generada.

Hay varios tipos de operaciones maintain: insert, update, delete y operaciones múltiples. Además, una operación maintain puede llamar a un servicio para hacer el trabajo (enviar un email, imprimir un informe, ...).

Puedes poner tantas operaciones como quieras dentro de un target. Por ejemplo, una operación insert seguida de dos operaciones update.

Motor de maintain
info

Nota: Todos los maintains se definen en el archivo Maintain.xml de la carpeta global. Consulta la estructura de proyecto para más información.

Maintain​

Esta sección describe cómo se realizan las operaciones con el motor de maintain de AWE.

Estructura XML del maintain​

La estructura del maintain simple es la siguiente:

<target name="[target_name]" public="[public]">
<[OPERATION] multiple="[multiple]" audit="[audit_table]">
<table id="[table_name]" schema="[schema_name]"/>
<field id="[field_name]" table="[table_name]" variable="[field_variable_name]" sequence="[sequence_name]"/>
<field id="[field_name]" table="[table_name]" variable="[field_variable_name]" auto-incremental="[true/false]"/>
... (more fields)
<where>
<and>
<filter left-field="[Field id]" condition="[Condition]" right-variable="[Variable]"/>
... (more filters)
<filter left-field="[Field id]" condition="[Condition]" right-variable="[Variable]"/>
</and>
</where>
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" list="[variable_list]"/>
<variable id="[variable_name]" type="[variable_type]" value="[static_value]" />
<variable id="[variable_name]" type="[variable_type]" session="[session_variable]"/>
... (more variables)

</[OPERATION]>
</target>

Nota: [OPERATION] puede ser cualquiera de los siguientes valores: insert, delete, update, multiple, commit, send-email, queue, serve o retrieve-data.

Elemento maintain​

Para facilitar el desarrollo de maintain, no todos los elementos son obligatorios.

ElementoUsoVarias instanciasDescripción
targetObligatorioNoDescribe el nombre de la operación
insertOpcionalSiSe usa para hacer operaciones de inserción en base de datos
updateOpcionalSiSe usa para hacer operaciones de actualización en base de datos
deleteOpcionalSiSe usa para hacer operaciones de borrado en base de datos
multipleOpcionalSiSe usa para hacer múltiples operaciones (insert, delete o update) en base de datos de una sola vez
commitOpcionalSiSe usa para hacer commit en base de datos y almacenar los cambios
serveOpcionalSiSe usa para hacer operaciones con servicios (servicios Java o Web)
queueOpcionalSiSe usa para hacer operaciones con colas
send-emailOpcionalSiEnvía emails
retrieve-dataOpcionalSiRecupera datos de SQL, servicios, enumerados o colas
tableOpcionalNoDescribe la tabla sobre la que se hacen los cambios
whereOpcionalNoDefine las condiciones que deben cumplirse para realizar la operación. Es la cláusula where de sql
fieldOpcionalSiDescribe las columnas de la tabla sobre la que se opera
constantOpcionalSiCampo constante para actualizar la tabla
operationOpcionalSiCampo de operación para actualizar la tabla
variableOpcionalSiSon los parámetros pasados a los maintains

Elemento target​

El elemento target tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
nameObligatorioStringIdentificador del maintainNota: El nombre debe ser único
publicOpcionalBooleanPara establecer que una query se pueda lanzar fuera de sesión (sin haber iniciado sesión)Por defecto es false
labelOpcionalStringSe usa para establecer el mensaje de salida tras ejecutar el mantenimientoNota: Puedes usar archivos i18n (locales)
exclusiveOpcionalBooleanPara restringir la ejecución concurrente del targetEstablece este atributo a true si no quieres que el target se ejecute de forma concurrente (varios usuarios a la vez)

Elemento table​

El elemento table tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
idObligatorioStringNombre de la tablaNota: Es el nombre real de la tabla en la base de datos
schemaOpcionalStringSe usa para establecer el usuario propietario de la tablaNota: Es el esquema (usuario) real de la tabla en la base de datos

Elemento where​

El elemento where tiene la siguiente estructura:

<target name="maintain">
...
<where>
<and>
<filter left-field="[Filter field]" left-table="[Filter table]" condition="[Condition]" right-variable="[Variable]" optional="[Filter Optional]"/>
<filter left-field="[Field 1]" left-table="[Filter table]" condition="[Condition]"
right-field="[Field 2]" right-table="[Table 2]" ignorecase="[Ignorecase]" trim="[Trim]"/>
<filter left-field="[Field]" left-table="[Filter table]" condition="[Condition]" right-query="[Subquery]"/>
<or>
... (more filters or filter groups)
</or>
... (more filters or filter groups)
</and>
<or>
... (more filters or filter groups)
</or>
</where>
...
</target>

Nota: Hay dos operadores disponibles para enlazar filtros. <and> y <or>

Elemento filter​

El comportamiento del elemento filter es el mismo que el del elemento filter de query.

Elemento field​

El elemento field en los maintains tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
idObligatorioStringNombre del campoNota: Es el nombre real de la columna de la tabla en la base de datos
tableOpcionalStringNombre de la tabla del campo
aliasOpcionalStringAlias del campo. Se usa para describir el campo
sequenceOpcionalStringNombre de la secuencia a insertar de la tabla AweKeyNota: Solo se aplica en maintains insert. Es obligatorio definir una nueva variable sin nombre para usarla y asignarla al atributo variable
auto-incrementalOpcionalBooleanSi el valor del campo se recupera de una columna de tipo identity/autoincrementalNota: Solo se aplica en maintains insert. Es obligatorio definir una nueva variable sin nombre para usarla y asignarla al atributo variable
keyOpcionalBooleanSi el campo es una clave de la tabla, este valor debe establecerse a trueNota: Solo se aplica en maintains multiple
auditOpcionalBooleanRegistra el campo SOLO en la tabla de auditoría. Nota: Si este atributo se establece a true este campo NO se registrará en la tablaEl valor por defecto es false
optionalOpcionalBooleanDeja este campo fuera de la operación cuando su variable no tiene valor, en lugar de escribir nullEl valor por defecto es false. Ver campos opcionales
variableOpcionalStringSe usa para establecer el campo de entrada con el valor de una variable
queryOpcionalStringEs el identificador de la query para hacer una subqueryNota: El id de la query debe existir
functionOpcionalStringPara aplicar una función sql al campoLos valores posibles se definen en funciones de campo
castOpcionalStringCambia el formato del campoLos valores posibles son STRING, INTEGER, LONG, FLOAT y DOUBLE

Campos opcionales​

Por defecto, cada field declarado llega a la sentencia generada, por lo que una variable sin valor escribe null en su columna. Con optional="true" el campo se deja fuera de la sentencia por completo cuando su variable no tiene valor:

  • en un insert, la columna toma su valor por defecto de la base de datos en lugar de null;
  • en un update, la columna conserva su valor almacenado en lugar de sobrescribirse con null.
<update audit="HISAweThm">
<table id="AweThm"/>
<field id="IdeThm" table="AweThm" variable="themeId"/>
<field id="Nam" table="AweThm" variable="themeName" optional="true"/>
<where>
<and>
<filter left-field="IdeThm" condition="eq" right-variable="themeId"/>
</and>
</where>
<variable id="themeId" type="INTEGER" name="themeId"/>
<variable id="themeName" type="STRING" name="themeName"/>
</update>

Enviar themeId sin themeName actualiza solo IdeThm; el Nam almacenado no se toca.

Nota: "Sin valor" significa nulo o vacío, la misma regla que optional ya sigue en los filtros de query, por lo que el atributo se comporta de forma coherente en ambos sitios.

Nota: El atributo se aplica a insert y update. Un delete no construye lista de campos, por lo que no le afecta.

Nota: Las tablas de auditoría no se ven afectadas: registran la operación que se solicitó y sus columnas admiten nulos, por lo que el histórico sigue conservando una fila para la columna omitida.

⚠️ Limitación: Un campo enlazado a una variable de tipo lista (un maintain por lotes) nunca se omite. Todas las filas de un lote comparten una única lista de columnas, por lo que dejar fuera una columna solo para una fila no es representable en la sentencia.

Elemento constant​

El elemento constant tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
idObligatorioStringNombre del campoNota: Es el nombre real de la columna de la tabla en la base de datos
tableOpcionalStringNombre de la tabla del campo
functionOpcionalStringPara aplicar una función sql al campoLos valores posibles se definen en funciones de campo
castOpcionalStringCambia el formato del campoLos valores posibles son STRING, INTEGER, LONG, FLOAT y DOUBLE
valueObligatorioStringUn valor estático a usar como valor del campo
typeOpcionalStringTipo del valorLos valores posibles están disponibles aquí

Elemento operation​

El elemento operation permite definir operaciones entre campos y se resolverá como cláusulas SQL:

<operation operator="[operator]" alias="[alias]">
<constant value="[constant value]" />
<field id="[field name]" table="[field table]" />
...
</operation>
AtributoUsoTipoDescripciónValores
idObligatorioStringNombre del campoNota: Es el nombre real de la columna de la tabla en la base de datos
tableOpcionalStringNombre de la tabla del campo
operatorObligatorioStringOperador de la operaciónVer atributo operator
functionOpcionalStringPara aplicar una función sql al campoLos valores posibles se definen en funciones de campo
castOpcionalStringCambia el formato del campoLos valores posibles son STRING, INTEGER, LONG, FLOAT y DOUBLE

Elemento variable​

El elemento variable en los maintains tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
idObligatorioStringEs el nombre identificador de la variableNota: El id debe ser único
typeObligatorioStringDescribe el tipo de la variablePuede ser STRING, INTEGER, etc.
nameOpcionalStringNombre de una variableLa variable es el nombre de un criterio definido en la pantalla
optionalOpcionalBooleanEstablecer este atributo a true evitará un error en caso de que no se pueda recuperar el valor de la variableEl valor por defecto es false
valueOpcionalStringValor
propertyOpcionalStringNombre de la propiedad
sessionOpcionalStringNombre de la variable de sesión

Maintain SQL​

Insert​

El elemento insert en los maintains tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
multipleOpcionalBooleanSi es true esta operación se lanzará tantas veces como valores tenga la variable de lista definida; si es audit esta operación se auditará tantas veces como valores tenga la variable de lista definidatrue, false o audit
labelOpcionalStringSe usa para establecer el mensaje de salida tras ejecutar el mantenimientoNota: Puedes usar archivos i18n (locales)
auditOpcionalStringEl nombre de la tabla de auditoría donde se van a almacenar los valores de auditoríaNota: La tabla de auditoría debe existir
queryOpcionalStringNombre de una query para recuperar datos de una sentencia INSERT INTO SELECTNota: Si también se define audit, AWE reutiliza el mismo conjunto de filas de origen para el insert base y las filas de auditoría
batchOpcionalBooleanRealiza la operación en lotesEl valor por defecto es false
batch-sizeOpcionalIntegerTamaño del loteEl valor por defecto es el definido en las propiedades

Nota: Puedes ver la información del elemento field aquí

La estructura del maintain insert es la siguiente:

<target name="[target_name]" public="[public]">
<insert multiple="[multiple]" audit="[audit_table]">
<table id="[table_name]"/>
<field id="[field_name]" table="[table_name]" variable="[field_variable_name]" sequence="[sequence_name]"/>
... (more fields)
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" list="[variable_list]"/>
<variable id="[variable_name]" type="[variable_type]" value="[static_value]" />
<variable id="[variable_name]" type="[variable_type]" session="[session_variable]"/>
... (more variables)
</insert>
</target>

Importante: el nombre del atributo sequence debe existir en la tabla AweKey

Ejemplos de INSERT​

<!-- Insert into AweQue table -->
<target name="QueNew">
<insert audit="HISAweQue">
<table id="AweQue"/>
<field id="IdeAweQue" sequence="JmsKey" variable="IdeAweQue"/>
<field id="Als" variable="Als"/>
<field id="Des" variable="Des"/>
<field id="QueTyp" variable="QueTyp"/>
<field id="Act" variable="Act"/>
<variable id="IdeAweQue" type="INTEGER" name="IdeAweQue" />
<variable id="Als" type="STRING" name="Als" />
<variable id="Des" type="STRING" name="Des" />
<variable id="QueTyp" type="STRING" name="QueTyp" />
<variable id="Act" type="INTEGER" name="Act" value="1"/>
</insert>
<commit/>
<serve service="RelJmsCon"/>
</target>
<!-- Insert with historic data -->
<target name="SitNew">
<insert audit="HISAweSit">
<table id="AweSit"/>
<field id="IdeSit" sequence="SitKey" variable="IdeSit"/>
<field id="Nam" variable="Nam"/>
<field id="Ord" variable="Ord"/>
<field id="Act" variable="Act"/>
<variable id="Nam" type="STRING" name="Nam" />
<variable id="Ord" type="INTEGER" name="Ord" />
<variable id="Act" type="INTEGER" name="Act" />
<variable id="IdeSit" type="INTEGER" name="IdeSit" />
</insert>
</target>

Inserts con columnas autoincrementales (IDENTITY/AUTO INCREMENT)​

Cuando la base de datos genera la clave primaria automáticamente (IDENTITY/AUTO INCREMENT), en las operaciones insert debes:

  • Marcar la columna autoincremental con auto-incremental="true" en el elemento field para que AWE recupere el id generado tras el insert.
  • Declarar una variable para ese campo que almacene el valor generado. No necesitas pasarla como entrada; AWE la rellenará con el id generado y puedes reutilizarla dentro del mismo target (por ejemplo, en operaciones posteriores) o devolverla al cliente.
  • No establecer sequence en columnas autoincrementales (las secuencias solo se aplican a las secuencias de AWE almacenadas en la tabla AweKey).

Ejemplo usando la tabla TestAutoIncrement (con id como IDENTITY):

<!-- Insert into a table with an auto‑increment (IDENTITY) primary key -->
<target name="TstAutoIncNew">
<insert>
<table id="TestAutoIncrement"/>
<!-- Mark the identity column as key and declare the variable to capture the generated id -->
<field id="id" auto-incremental="true" variable="id"/>
<field id="name" variable="name"/>
<field id="email" variable="email"/>

<!-- Input variables -->
<variable id="name" type="STRING" name="name"/>
<variable id="email" type="STRING" name="email"/>

<!-- Output variable that will hold the generated id after the insert -->
<variable id="id" type="INTEGER"/>
</insert>
</target>

Nota: En los maintains multiple, también es obligatorio tener un field con auto-incremental="true" para indicar la clave de la tabla. La misma convención se aplica cuando la clave la genera la base de datos.

Ejemplo reutilizando el id generado en un insert posterior (el padre tst_order y sus filas tst_order_item):

<target name="insertWithKeySingle">
<!-- First insert: capture the generated OrderId from tst_order.id -->
<insert>
<table id="tst_order"/>
<!-- Mark the identity column as auto-incremental="true" and declare the variable to capture the generated id -->
<field id="id" auto-incremental="true" variable="OrderId"/>
<field id="order_date" variable="OrderDate"/>
<constant id="order_comments" value="Test Order"/>

<variable id="OrderDate" type="SYSTEM_DATE" name="OrderDate"/>
<!-- Output variable filled by AWE with the generated id -->
<variable id="OrderId" type="INTEGER" name="OrderId"/>
</insert>

<!-- Second insert (multiple): reuse OrderId to insert order items -->
<insert multiple="true">
<table id="tst_order_item"/>
<field id="order_id" variable="OrderId"/>
<field id="order_product" variable="ProductName"/>
<field id="order_price" variable="ProductPrice"/>
<field id="order_quantity" variable="ProductQuantity"/>

<variable id="OrderId" type="INTEGER" name="OrderId"/>
<variable id="ProductName" type="STRING" name="order_product"/>
<variable id="ProductPrice" type="FLOAT" name="order_price"/>
<variable id="ProductQuantity" type="INTEGER" name="order_quantity"/>
</insert>
</target>

Insert into select​

La sentencia INSERT INTO SELECT es otra forma de hacer una sentencia insert, pero recuperando los datos de una subquery. La estructura de una sentencia INSERT INTO SELECT es la siguiente:

<target name="[target_name]" public="[public]">
<insert query="[query_to_retrieve_data_from]">
<table id="[table_name]"/>
<field id="[field_name]"/>
... (more fields)
</insert>
</target>

Nota: El número de campos definidos en la sentencia INSERT INTO SELECT y en la subquery debe coincidir.

Nota: Cuando audit se define junto con query, las filas de auditoría se generan a partir de las mismas filas de origen que usa el insert base. Las queries de origen vacías insertan cero filas base y cero filas de auditoría.

Ejemplos de INSERT INTO SELECT​

<!-- Insert into select (maintain.xml) -->
<target name="test">
<insert query="testData">
<table id="test"/>
<field id="Nam"/>
<field id="Ord"/>
</insert>
</target>

<!-- Query for data retrieving (queries.xml) -->
<query id="testData" distinct="true">
<table id="AweKey" />
<field id="KeyNam"/>
<field id="Act"/>
</query>

Esto generará el siguiente código SQL:

INSERT INTO test (Nam, Ord) SELECT DISTINCT KeyNam, Act FROM AweKey

Update​

El elemento update en los maintains tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
multipleOpcionalBooleanSi es true esta operación se lanzará tantas veces como valores tenga la variable de lista definida; si es audit esta operación se auditará tantas veces como valores tenga la variable de lista definidatrue, false o audit
labelOpcionalStringSe usa para establecer el mensaje de salida tras ejecutar el mantenimientoNota: Puedes usar archivos i18n (locales)
auditOpcionalStringEl nombre de la tabla de auditoría donde se van a almacenar los valores de auditoríaNota: La tabla de auditoría debe existir
batchOpcionalBooleanRealiza la operación en lotesEl valor por defecto es false
batch-sizeOpcionalIntegerTamaño del loteEl valor por defecto es el definido en las propiedades

Nota: Puedes ver la información del elemento where aquí

La estructura del maintain update es la siguiente:

<target name="[target_name]" public="[public]">
<update multiple="[multiple]" audit="[audit_table]">
<table id="[table_name]"/>
<field id="[field_name]" table="[table_name]" variable="[field_variable_name]" audit="[audit]"/>
... (more fields)
<where>
<and>
<filter left-field="[filter_field]" left-table="[filter_field_table]" condition="[filter_condition]"
right-variable="[filter_variable]" ignorecase="[filter_ignore_case]" trim="[filter_trim]"/>
... (more filters)
</and>
</where>
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" list="[variable_list]"/>
<variable id="[variable_name]" type="[variable_type]" value="[static_value]" />
<variable id="[variable_name]" type="[variable_type]" session="[session_variable]"/>
... (more variables)
</update>
</target>

Ejemplos de update​

<!-- Manage User as logged out -->
<target name="MgrUsrLogOut" public="true">
<!-- Mark User as logged out -->
<update>
<table id="ope"/>
<field id="l1_con" variable="Con"/>
<field id="l1_dat" variable="SysDat"/>
<where>
<and>
<filter left-field="l1_nom" condition="eq" right-variable="Usr" ignorecase="true"/>
</and>
</where>
<variable id="Con" type="INTEGER" value="0"/>
<variable id="SysDat" type="SYSTEM_DATE" />
<variable id="Usr" type="STRING" session="user" optional="false"/>
</update>
</target>
<target name="UsrUpd">
<update>
<table id="ope"/>
<field id="l1_act" variable="Sta"/>
<field id="WebPrn" variable="WebPrn"/>
<field id="PcPrn" variable="PcPrn"/>
<field id="EmlAdr" variable="Eml"/>
<field id="EmlSrv" variable="EmlSrv"/>
<field id="l1_lan" variable="Lan"/>
<field id="OpeNam" variable="Nam"/>
<field id="IdePro" variable="Pro"/>
<field id="IdeThm" variable="Thm"/>
<field id="ScrIni" variable="ScrIni"/>
<field id="Res" variable="Res"/>
<field id="PwdLck" variable="PwdLck"/>
<where>
<and>
<filter left-field="IdeOpe" condition="eq" right-variable="IdeOpe"/>
</and>
</where>
<variable id="IdeOpe" type="INTEGER" name="IdeOpe" />
<variable id="Sta" type="INTEGER" name="Sta" />
<variable id="WebPrn" type="STRINGN" name="WebPrn" />
<variable id="PcPrn" type="STRINGN" name="PcPrn" />
<variable id="Eml" type="STRINGN" name="Eml" />
<variable id="EmlSrv" type="STRINGN" name="EmlSrv" />
<variable id="Lan" type="STRINGN" name="Lan" />
<variable id="Nam" type="STRINGN" name="Nam" />
<variable id="Pro" type="INTEGER" name="Pro" />
<variable id="Thm" type="INTEGER" name="Thm" />
<variable id="ScrIni" type="STRING" name="ScrIni" />
<variable id="Res" type="STRING" name="Res" />
<variable id="PwdLck" type="INTEGER" name="PwdLck" />
</update>
</target>

Delete​

El elemento delete en los maintains tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
multipleOpcionalBooleanSi es true esta operación se lanzará tantas veces como valores tenga la variable de lista definida; si es audit esta operación se auditará tantas veces como valores tenga la variable de lista definidatrue, false o audit
labelOpcionalStringSe usa para establecer el mensaje de salida tras ejecutar el mantenimientoNota: Puedes usar archivos i18n (locales)
auditOpcionalStringEl nombre de la tabla de auditoría donde se van a almacenar los valores de auditoríaNota: La tabla de auditoría debe existir
batchOpcionalBooleanRealiza la operación en lotesEl valor por defecto es false
batch-sizeOpcionalIntegerTamaño del loteEl valor por defecto es el definido en las propiedades

Nota: Puedes ver la información del elemento where aquí

La estructura del maintain delete es la siguiente:

<target name="[target_name]" public="[public]">
<delete multiple="[multiple]" audit="[audit_table]">
<table id="[table_name]"/>
<field id="[field_name]" table="[table_name]" variable="[field_variable_name]" audit="[audit]"/>
<where>
<and>
<filter left-field="[filter_field]" left-table="[filter_field_table]" condition="[filter_condition]"
right-variable="[filter_variable]" ignorecase="[filter_ignore_case]" trim="[filter_trim]"/>
... (more filters)
</and>
</where>
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" list="[variable_list]"/>
<variable id="[variable_name]" type="[variable_type]" value="[static_value]" />
<variable id="[variable_name]" type="[variable_type]" session="[session_variable]"/>
... (more variables)
</delete>
</target>

Ejemplos de delete​

<!-- Delete maintain with historic operation -->
<target name="ProDel">
<delete audit="HISAweModPro">
<table id="AweModPro"/>
<field id="IdePro" variable="IdePro" audit="true"/>
<where>
<and>
<filter left-field="IdePro" condition="eq" right-variable="IdePro" />
</and>
</where>
<variable id="IdePro" type="INTEGER" name="IdePro"/>
</delete>
</target>
<!-- Delete maintain with multiple atributte -->
<target name="UsrDel">
<delete multiple="true">
<table id="ope"/>
<where>
<and>
<filter left-field="IdeOpe" condition="eq" right-variable="IdeOpe"/>
</and>
</where>
<variable id="IdeOpe" type="INTEGER" name="IdeOpe"/>
</delete>
</target>

Multiple​

Los maintains multiple se usan en el widget Grid para realizar operaciones sql.

El elemento multiple en los maintains tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
gridObligatorioStringEs el nombre del grid donde se realizan las operaciones
labelOpcionalStringSe usa para establecer el mensaje de salida tras ejecutar el mantenimientoNota: Puedes usar archivos i18n (locales)
auditOpcionalStringEl nombre de la tabla de auditoría donde se van a almacenar los valores de auditoríaNota: La tabla de auditoría debe existir

IMPORTANTE: Debe existir un campo con el atributo key="true" para indicar qué campo es la clave de la tabla

Ejemplos de multiple​

<!-- Screen Access Multiple -->
<target name="ScrAccUpd">
<multiple audit="HISAweScrRes" grid="GrdScrAccLst">
<table id="AweScrRes"/>
<field id="IdeAweScrRes" variable="IdeAweScrRes" sequence="ScrResKey" key="true"/>
<field id="IdePro" variable="IdePro"/>
<field id="IdeOpe" variable="IdeOpe"/>
<field id="IdeMod" variable="IdeMod"/>
<field id="Opt" variable="Opt"/>
<field id="AccMod" variable="AccMod"/>
<field id="Act" variable="Act"/>
<variable id="IdeAweScrRes" type="INTEGER" name="IdeAweScrRes"/>
<variable id="IdeOpe" type="INTEGER" name="IdeOpe" optional="true"/>
<variable id="IdePro" type="INTEGER" name="IdePro" optional="true"/>
<variable id="IdeMod" type="INTEGER" name="IdeMod" optional="true"/>
<variable id="Opt" type="STRING" name="Opt" />
<variable id="AccMod" type="STRING" name="AccMod"/>
<variable id="Act" type="INTEGER" name="Act" />
</multiple>
</target>
<!-- AweKey Update Multiple -->
<target name="AweKeyUpd">
<multiple grid="GrdKeyLst">
<table id="AweKey"/>
<field id="KeyNam" variable="KeyNam" key="true"/>
<field id="KeyVal" variable="KeyVal"/>
<field id="Act" variable="Act"/>
<variable id="KeyNam" type="STRING" name="KeyNam"/>
<variable id="KeyVal" type="INTEGER" name="KeyVal"/>
<variable id="Act" type="INTEGER" name="Act"/>
</multiple>
</target>

Auditorías​

Las auditorías las gestiona AWE automáticamente, pero las tablas de auditoría deben crearse en tiempo de desarrollo y necesitan tener al menos tres campos clave:

  • Usuario de auditoría - Usuario que realiza la operación
  • Marca de tiempo de auditoría - Fecha y hora de la operación de auditoría
  • Tipo de auditoría - Operación de inserción (I), actualización (U) o borrado (D)

Commit​

La etiqueta <commit/> se usa dentro de los targets de maintain para forzar que los datos se guarden en la base de datos. Normalmente se usa entre distintas operaciones de mantenimiento para asegurar que los datos son correctos antes de pasar al siguiente paso. Consulte Transacciones para ver cómo funciona con la transacción del maintain.

Ejemplo de commit​

<!-- Do commit before execute service operation -->
<target name="DbsDel">
<delete multiple="true" audit="HISAweSitModDbs">
<table id="AweSitModDbs"/>
<field id="IdeDbs" variable="IdeDbs" audit="true"/>
<where>
<and>
<filter left-field="IdeDbs" condition="eq" right-variable="IdeDbs" />
</and>
</where>
<variable id="IdeDbs" type="INTEGER" name="IdeDbs"/>
</delete>
<delete multiple="true" audit="HISAweDbs">
<table id="AweDbs"/>
<field id="IdeDbs" variable="IdeDbs" audit="true" />
<field id="Als" variable="Als" audit="true" />
<field id="Des" variable="Des" audit="true" />
<field id="Dct" variable="Dct" audit="true" />
<field id="Typ" variable="Typ" audit="true" />
<field id="Dbt" variable="Dbt" audit="true" />
<field id="Dbc" variable="Dbc" audit="true" />
<where>
<and>
<filter left-field="IdeDbs" condition="eq" right-variable="IdeDbs" />
</and>
</where>
<variable id="IdeDbs" type="INTEGER" name="IdeDbs" />
<variable id="Als" type="STRING" name="Als" />
<variable id="Des" type="STRINGN" name="Des" />
<variable id="Dct" type="STRING" name="Dct" />
<variable id="Dbt" type="STRING" name="Dbt" />
<variable id="Typ" type="STRING" name="Typ" />
<variable id="Dbc" type="STRING" name="Dbc" />
</delete>
<commit/>
<serve service="RelDbsCon"/>
</target>

Transacciones​

Cada maintain se ejecuta dentro de una transacción de base de datos de su datasource. Si el maintain termina sin error, la transacción se confirma; si una sentencia falla, o un paso devuelve un resultado ERROR, se deshace el maintain completo. Lo controla awe.maintain.transaction.enabled (true por defecto, nuevo en AWE 5).

# Valor por defecto. Póngalo a false para recuperar el comportamiento de AWE 4 descrito más abajo
awe.maintain.transaction.enabled=true

Qué cubre la transacción​

La transacción pertenece al datasource del maintain: el datasource por defecto, o el que se elige con el parámetro de base de datos cuando awe.database.multidatabase-enable=true. Todo lo que se ejecuta sobre ese datasource mientras dura el maintain se une a ella (PROPAGATION_REQUIRED de Spring):

Paso del maintainCon la transacción (por defecto)
insert, update, delete, multiple, auditorías (tablas HIS*), include-targetLa misma transacción. Un fallo deshace todas las sentencias anteriores del maintain.
retrieve-dataSe une a la transacción, así que ve las filas que el mismo maintain escribió antes.
serve con un servicio Java que lanza otro maintain sobre el mismo datasourceEl maintain anidado se une al exterior: se confirma o se deshace con él.
Un paso que devuelve un ServiceData de tipo ERROR sin lanzar excepciónSe deshace el maintain y se devuelve la respuesta de error tal cual.
<commit/>Confirma la transacción a mitad del maintain, como antes: lo anterior se mantiene aunque falle un paso posterior.
Un maintain lanzado dentro de un método @Transactional (o un TransactionTemplate) de la aplicación sobre el mismo datasourceSe une a la transacción de la aplicación: se confirma o se deshace con ella.
Un maintain sobre otro datasourceSe ejecuta en su propia transacción de ese datasource.
Pasos queue (JMS) y emailNo son transaccionales: un rollback no deshace un mensaje o un correo ya enviados.
Llamadas REST y de microservicio (serve con un servicio REST o de microservicio)No son transaccionales: el lado remoto no se deshace.

Tenga en cuenta:

  • Un fallo silenciado también deshace. Si un servicio Java captura la excepción de un maintain anidado, o ignora su resultado ERROR, y devuelve OK, el maintain exterior falla al confirmar con el error genérico de maintain y se deshace todo. Deje que el error se propague en lugar de ocultarlo.
  • Dentro de una transacción de la aplicación, un maintain que falla solo la marca para deshacer. Sus filas se deshacen cuando termina la transacción de la aplicación, no antes: hasta entonces esa misma transacción las sigue viendo, y confirmarla falla con la UnexpectedRollbackException de Spring.
  • <commit/> en un maintain anidado confirma también el trabajo del exterior, porque ambos comparten la conexión.
  • El código Java que llama a las sobrecargas de launchMaintain o launchPrivateMaintain que reciben el identificador del maintain y un DatabaseConnection es dueño de esa conexión: AWE no abre una transacción para ella y mantiene el comportamiento de AWE 4 (confirmar y liberar al final, o nada con keepAliveConnection=true). La sobrecarga launchMaintain(Target, ...) sí abre la transacción cuando el DatabaseConnection aún no ha obtenido su conexión.
  • Para unirse hace falta el mismo objeto DataSource. Con awe.database.multidatabase-enable=true, un maintain sin el parámetro de base de datos usa el datasource de enrutado, y uno con un alias explícito usa el pool de ese alias. No se unen entre sí aunque ambos apunten a la misma base de datos física.
  • Listeners JMS. El contenedor de listeners JMS de AWE usa el gestor de transacciones de Spring Boot, así que un maintain lanzado desde un listener de cola se une a la transacción del listener (en AWE 4 confirmaba por su cuenta).
  • Broadcasts antes del commit. Un broadcast de notificación (notifier) enviado desde un paso de un maintain largo puede llegar al cliente antes de que el maintain confirme, así que el cliente quizá aún no vea la fila.

Desactivarla (comportamiento de AWE 4)​

Con awe.maintain.transaction.enabled=false los maintains se comportan como en AWE 4:

  • Cada maintain desactiva el auto-commit de su propia conexión, confirma al final y deshace sus propias sentencias si hay una excepción.
  • retrieve-data y los maintains anidados lanzados desde servicios Java usan otras conexiones: un maintain anidado confirma por su cuenta, así que sigue confirmado aunque el exterior falle después, y retrieve-data no ve las filas sin confirmar del maintain.
  • Un paso que devuelve un resultado ERROR sin excepción no deshace nada: el maintain se confirma.
  • Un maintain lanzado dentro de una transacción de la aplicación confirma en su propia conexión.

Desactívela solo si una aplicación depende de estas confirmaciones parciales, por ejemplo un servicio Java que debe conservar las filas de un maintain anidado aunque el exterior falle. En ese caso, es preferible mover ese trabajo a su propio maintain, lanzado después del exterior.

Ciclo de vida de la conexión por conector​

Auditoría de cómo obtiene y libera cada conector su conexión (incidencia #781):

ConectorConexiónCommit y rollback
SQLMaintainConnector / SQLMaintainBuilder (insert, update, delete, multiple, auditorías, lotes)La conexión del maintain, que le pasa MaintainService.No tiene propios: los gestiona MaintainService (o la transacción). Los errores se propagan como AWEQueryException.
SQLQueryConnector (retrieve-data, queries)DataSourceUtils.getConnection sobre el datasource, liberada tras la query.Ninguno. Se une a la transacción del maintain si la hay; si no, es una conexión aparte.
ServiceMaintainConnector → JavaConnector, RestConnector, MicroserviceConnectorNo se pasa ninguna conexión al servicio. Los maintains que lanza un servicio Java toman la conexión de la transacción activa de su datasource, o una nueva.Servicios Java: los de los maintains que lanzan. REST y microservicio: remotos, no transaccionales. Un servicio Java que devuelve ERROR sin excepción solo provoca rollback con la transacción activada.
QueueMaintainConnector / QueueBuilderNinguna conexión JDBC (JmsTemplate).Los mensajes se envían al momento; un rollback no los deshace.
EmailMaintainConnector / EmailServiceSus queries usan QueryService (ver SQLQueryConnector).Los correos se envían al momento; un rollback no los deshace.
MaintainService.getNextSequenceValueLa conexión que recibe (o una nueva), que siempre libera al final.Ninguno.

Otros hallazgos de la auditoría: DatabaseConnection.getConnection() devuelve null cuando el datasource no puede dar una conexión (con la transacción activada el maintain falla en cambio al empezar la transacción); en el camino de AWE 4 no se restaura el auto-commit antes de liberar la conexión (Hikari lo restaura al devolverla al pool); y un rollback que falla oculta el error original en ambos caminos.

Maintain de servicio​

Se usan para llamar a servicios (servicios Java o Web) desde una operación maintain.

El maintain de servicio tiene la siguiente estructura xml:

<target name="[target_name]" exclusive="[exclusive]" public="[public]">
<serve service="[service_name]">
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]"/>
<variable id="[variable_name]" type="[variable_type]" value="[static_value]"/>
<variable id="[variable_name]" type="[variable_type]" session="[session_variable]"/>
... (more variables)
</serve>
</target>

IMPORTANTE: El maintain de servicio debe tener el elemento <serve>. El nombre del servicio debe existir en el archivo Services.xml. Puedes ver servicios para más información.

El elemento serve en los maintains tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
serviceObligatorioStringIdentificador del servicioNota: El id del servicio debe existir en el archivo Services.xml
labelOpcionalStringSe usa para establecer el mensaje de salida tras ejecutar el mantenimientoNota: Puedes usar archivos i18n (locales)

Ejemplos de maintain de servicio​

<!-- Serve example -->
<target name="[target_name]">
<serve service="RelAllScrCfg" />
<serve service="LoaScrCfgByDbs">
<variable id="database" type="STRING" session="database"/>
</serve>
</target>
<!-- Clear profile Cache -->
<target name="ClrCchPrf">
<serve service="ClrCch">
<variable id="cache" type="STRING" value="PROFILE"/>
</serve>
</target>

Maintain de cola​

Se usan para enviar mensajes a una cola Jms desde una operación maintain.

El maintain de cola tiene la siguiente estructura xml:

<target name="[target_name]" >
<queue name="[Id_queue]">
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" [[list="list"]
[session="session_variable"] [value="static_value"] [property="property_value"]]/>
... (more variables)
</queue>
</target>

IMPORTANTE: El maintain de cola debe tener el elemento <queue>. El nombre de la cola debe existir en el archivo Queues.xml. Puedes ver colas para más información.

El elemento queue en los maintains tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
nameObligatorioStringIdentificador de la colaNota: El id de la cola debe existir en el archivo Queues.xml
labelOpcionalStringSe usa para establecer el mensaje de salida tras ejecutar el mantenimientoNota: Puedes usar archivos i18n (locales)

Ejemplos de maintain de cola​

<!-- Test queues -->
<target name="TstQueSndSyn">
<queue name="TstQueSndSyn">
<variable id="Usr" type="STRING" name="CrtNam"/>
</queue>
</target>

Maintain de email​

Se usan para enviar emails desde una operación maintain.

El maintain de email tiene la siguiente estructura xml:

<target name="[target_name]" >
<send-email name="[Email Id]">
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" [[list="list"]
[session="session_variable"] [value="static_value"] [property="property_value"]]/>
... (more variables)
</send-email>
</target>

IMPORTANTE: El maintain de email debe tener el elemento <send-email>. El identificador del email debe existir en el archivo Email.xml. Puedes ver definición de email para más información.

El elemento email en los maintains tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
idObligatorioStringIdentificador del emailNota: El id del email debe existir en el archivo Email.xml
labelOpcionalStringSe usa para establecer el mensaje de salida tras ejecutar el mantenimientoNota: Puedes usar archivos i18n (locales)

Ejemplos de maintain de email​

<!-- Send reports by e-mail -->
<target name="SndRep">
<send-email id="SndRep"/>
</target>

Include target​

Puedes añadir una etiqueta include-target para reutilizar targets ya definidos en lugar de reescribirlos.

Include target tiene la siguiente estructura xml:

<target name="[Target name]" >
<include-target name="[target-to-include]"/>
</target>

IMPORTANTE: Include target debe tener el elemento <include-target>. El [target-to-include] debe existir en alguno de los archivos Maintain.xml.

Include target tiene los siguientes atributos:

AtributoUsoTipoDescripciónValores
nameObligatorioStringIdentificador del targetNota: El nombre del target debe existir en el archivo Maintain.xml

Ejemplos de include target​

<!-- Test insert -->
<target name="testInsert">
<insert>
<table id="HISAweMod" />
<field id="HISope" variable="User" />
<field id="HISdat" variable="Date" />
<field id="HISact" variable="Action" />
<field id="Nam" variable="Nam" />
<field id="IdeThm" variable="Thm" />
<field id="ScrIni" variable="Scr" />
<field id="Act" variable="Act" />
<variable id="Nam" type="STRING" value="testIncludeTarget" />
<variable id="Thm" type="INTEGER" value="1" />
<variable id="Scr" type="STRING" value="testIncludeTarget" />
<variable id="Act" type="INTEGER" value="1" />
<variable id="User" type="STRING" value="testIncludeTarget" />
<variable id="Date" type="SYSTEM_DATE"/>
<variable id="Action" type="STRING" value="T" />
</insert>
</target>

<!-- Test update -->
<target name="testUpdate">
<update>
<table id="HISAweMod" />
<field id="Nam" variable="Nam" />
<field id="IdeThm" variable="Thm" />
<field id="ScrIni" variable="Scr" />
<field id="Act" variable="Act" />
<where>
<and>
<filter left-field="HISope" condition="eq" right-variable="User"/>
<filter left-field="HISact" condition="eq" right-variable="Action"/>
</and>
</where>
<variable id="Nam" type="STRING" value="testIncludeTargetUpd" />
<variable id="Thm" type="INTEGER" value="2" />
<variable id="Scr" type="STRING" value="testIncludeTargetUpd" />
<variable id="Act" type="INTEGER" value="2" />
<variable id="User" type="STRING" value="testIncludeTarget" />
<variable id="Action" type="STRING" value="T" />
</update>
</target>

<!-- Test delete -->
<target name="testDelete">
<delete>
<table id="HISAweMod" />
<where>
<and>
<filter left-field="HISope" condition="eq" right-variable="User"/>
<filter left-field="HISact" condition="eq" right-variable="Action"/>
</and>
</where>
<variable id="User" type="STRING" value="testIncludeTarget" />
<variable id="Action" type="STRING" value="T" />
</delete>
</target>

<!-- Test include -->
<target name="testInclude">
<include-target name="testInsert"/>
<include-target name="testUpdate"/>
<include-target name="testDelete"/>
</target>

Retrieve data​

El target retrieve data es útil para recuperar datos de una query (SQL, servicio, enumerado, etc.) y enviarlos a un proceso maintain.

Retrieve data tiene la siguiente estructura xml:

<target name="[target_name]">
<retrieve-data service="[service_id]" enumerated="[enumerated_id]" queue="[queue_id]">
<table .../>
<field alias="[field_alias]"
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" [[list="list"]
[session="session_variable"] [value="static_value"] [property="property_value"]]/>
... (more variables)
</retrieve-data>
</target>

La etiqueta retrieve-data funciona como una query definida en queries.xml. Cada columna recuperada se almacenará como un parámetro con el nombre del alias del campo.

NOTA: Si estás usando secuencias de AWE, deberías considerar priorizar esta forma de recuperar datos para insertarlos en lugar de las sentencias INSERT INTO SELECT.

Ejemplos de retrieve data​

<target name="testRetrieveDataAndInsertAfter">
<retrieve-data>
<table id="Table1"/>
<field id="Field1" alias="name"/>
<field id="Field2" alias="screen"/>
<field id="Field3" alias="user"/>
<field id="Field4" alias="action"/>
</retrieve-data>
<insert multiple="true">
<table id="Table2"/>
<field id="User" variable="User"/>
<field id="Date" variable="Date"/>
<field id="Action" variable="Action"/>
<field id="Name" variable="Nam"/>
<field id="Active" variable="Active"/>
<variable id="User" type="STRING" name="user"/>
<variable id="Date" type="SYSTEM_DATE"/>
<variable id="Action" type="STRING" name="action"/>
<variable id="Name" type="STRING" name="name"/>
<variable id="Active" type="INTEGER" value="1"/>
</insert>
</target>

Este ejemplo recuperará una lista de variables llamadas name, screen, user y action y las usará como parámetros de entrada de la sentencia insert a Table2.