GrialTransaction

De GrialWIKI

Introducción al Framework Grial

Índice

Contenido

Actualización de la Base de Datos: GrialTransaction

Las transacciones en el Entorno Grial son preparadas en el cliente, y luego enviadas como un conjunto único al Servidor intermedio. El objeto utilizado para componer una transacción es el GrialTransaction. Los objetos de esta clase funcionan como una "pila" en la cual se acumulan los ítems que conforman la transacción recordsets con modificaciones y/o comandos SQL (con las extensiones aceptadas por el GrialDataServer). Una vez armada la transacción, mediante el método GrialCont.Apply se envía el conjunto al servidor para su proceso.

La transacción se prepara mediante el método "Add", que es el que coloca en la pila cada uno de los ítems que la componen. Los ítems deben ser agregados en la transacción en un orden cabecera-detalle, haciendo seguir a cada recordset con registros de cabecera del recordset con registros de detalle dependientes de los anteriores. Por default, al aplicar la transacción, el GrialDataServer asume que los registros de cabecera de un ítem dado se hallan en el ítem inmediato anterior.

Formato:

Sub Add( SqlCmd_or_Recordset, [Rela_String As String] )

Ejemplo:

 Dim Txn As New GrialTransaction
 Txn.Add PreForm20_grq.Rst , "ID_PREFORM20"
 Txn.Add PreForm21_grq.Rst , "ID_PREFORM21;RELA_PREFORM20"
 Txn.Add PreForm23_grq.Rst , ";RELA_PREFORM21"
 ' Aplico la transacción en el Servidor 
 Txn.Apply GrialCont

El primer parámetro del método Add es un recordset con las modificaciones realizadas o puede ser también un string conteniendo un query o un comando a ejecutar en la BD.

Indicando las Relaciones Cabecera/Detalle

El segundo parámetro del método Add establece propiedades para el ítem dentro de la transacción, mediante una sintaxis especial.

Cuenta con dos secciones separadas por el carácter dos puntos : , la primer sección es opcional y permite dar nombre a una cabecera, actualizar campos de tipo fecha y considerar casos especiales.

La segunda sección (fija) se compone de hasta tres nombres de campo, separados por ;

El primer nombre de campo es el ID de la tabla, el segundo es el campo RELA al recordset de cabecera (para recordsets de detalles) y el tercero es el campo RELA_PADRE (sólo para las tablas de tipo ARB, árboles).

Como los recordsets en la transacción se ordenan primero las tablas cabeceras y luego los detalles, dentro de la transacción se asume que si en un Add se indica un campo RELA, la tabla cabecera es la indicada en el ítem inmediato superior.

Ejemplos:

 Txn.Add PreForm20_grq.Rst , "ID_PREFORM20" ' Cabecera
 Txn.Add PreForm21_grq.Rst , "ID_PREFORM21;RELA_PREFORM20" 'Detalle de la 20, el rela es 
                                                           'al ítem inmediato superior
 Txn.Add PreForm07_grq.Rst , "ID_PREFORM07;;RELA_PADRE" 'Tabla tipo ARBOL
                                                        '(RELA_PADRE es un rela a sí misma)

Primera Sección. (En .NET es posible indicar todos los campos en la primera sección, opcional en VB6)

La primer sección opcional de datos (hasta el caracter : o hasta el fin del string) contiene propiedades para el ítem de la transacción y da la posibilidad de modificar el orden cabecera-detalle o de actualizar tablas con múltiples campos RELA.

El Formato es: "Parametro = valor, Parametro = valor ... :"

Los parámetros pueden ser:

NAME = xxxx -- Identifica el ítem (recordset) de la transacción con un nombre, se usa para luego referenciarlo como cabecera o para identificar un resultado

ID= xxxx -- Nombre del campo ID (solo .NET)

RELA = yyyy --Nombre del Campo Rela (solo .NET)

HEADER = hhhh -- Indica cual es el ítem (identificado previamente mediante NAME = xxxx ) que contiene los registros cabecera. Es necesario sólo cuando la cabecera y el detalle no se pueden colocar uno a continuación de otro en la transacción, o cuando hay más de un detalle para una cabecera.

RelaField= FIELD_NAME / HEADER_NAME -- Se usa para actualizar un registro que tiene más de un campo RELA. Reemplaza el valor del campo indicado por el valor de ID tomado del header indicado. Por ejemplo: "RelaField=rela_preform20_ORIG/PF20: ... "

RELASelf = sss --Nombre del Campo Rela a sí mismo (TREE) (solo .NET, por ejemplo: RELASelf=RELA_PADRE,...)

Por ejemplo:

 Txn.Add PreForm20_grq.Rst , "Name=PF20, ID=ID_PREFORM20" ' Cabecera
 Txn.Add PreForm07_grq.Rst , "ID=ID_PREFORM07, RELASelf=RELA_PADRE" ' Actualizo un arbol
 Txn.Add PreForm21_grq.Rst , "ID=ID_PREFORM21, RelaField=RELA_PREFORM20/PF20" ' .../PF20 => la cabcecera no es el inmediato anterior


Supongamos que una tabla PRE_EJEC_22 tiene un RELA_PREEJEC21 y además tiene un RELA_PREEJEC20, y se dan de alta las tres tablas en la misma transacción. Serían la PRE_EJEC_20 (cabecera), PRE_EJEC_21 (detalle), PRE_EJEC_22 (detalle secundario, con dos relas)

 Txn.Add PreForm20_grq.Rst , "Name=PE20: ID_PREFORM20" ' Cabecera
 Txn.Add PreForm21_grq.Rst , "ID_PREFORM21;RELA_PREFORM20" 'Detalle
 Txn.Add PreForm22_grq.Rst , "RelaField=RELA_PREEJEC20/PE20: ID_PREFORM22;RELA_PREFORM21" 
                              'El 3er item es Detalle del 2do, pero tiene también
                              'un rela a la cabecera principal (RELA_PREEJEC20)

SysDateField = FIELD_NAME/FIELD_NAME... -- Se usa para los campos que deben ser actualizados con la fecha del sistema. Reemplaza los campos indicados por el Sysdate de la máquina donde corre el Servidor de Aplicaciones. Debe indicarse para efectuar un registro preciso de fechas y horas, ya que la máquina cliente donde se prepara la transacción puede tener mal la fecha. En caso de un ALTA, se actualizarán los campos indicados, siempre que contengan valores no-nulos. En caso de MODIFICACION, se actualizarán los campos indicados con la fecha del sistema sólo si fue modificado su valor original

En el módulo cliente, debe indicarse siempre el "SysdateField=field1/field2/..." y se deben cargar/modificar los campos utilizando la función "Now" (sysdate de la terminal, valor no-confiable).

Por ejemplo: "SysDateField=PREEJEC40_FECHA_ACTUALIZA:...

Cuando el servidor actualice el recordset en la base, reemplazará los valores en PREEJEC40_FECHA_ACTUALIZA por el sysdate del servidor (valor confiable).

Nota: Para los campos con nombre: FAPL, FBAJA, FANULADO, WFFECHACURSO, WFFECHA se realiza esta actualización con la fecha del servidor automáticamente.

Segunda Sección (fija)

Formato: Hasta 3 campos separados por ;

ID_FIELDNAME: Nombre del Campo que contiene el ID de la tabla. Se usará para tomar el valor que debe ser grabado en los campos RELA de los siguientes detalles.

RELA_FIELDNAME: Nombre del campo que contiene el ID de la cabecera (por default en el recordset anterior). La combinación de ID_FieldName de un ítem y el RELA_FieldName del ítem siguiente establecen una relación cabecera-detalle.

RELA_PADRE: Cuando un recordset establece relaciones dentro de sí mismo. Por ejemplo una tabla tipo árbol. RELA_PADRE es el nombre del campo que representa la relación padre-hijo dentro de la jerarquía del árbol. La combinación ID_FieldName + RELA_PADRE en un mismo recordset se utiliza para las tablas tipo árbol.

Ejemplos de Armado y Aplicación de Transacciones

1.- CABECERA + DETALLE

    Dim Cabecera_PAREXA02_grq as New [[GrialQuery]]
    Dim Detalle_PAREXA03_grq as New GrialQuery
    ...
    Dim Txn As New GrialTransaction
 
    Txn.Add Cabecera_PAREXA02_grq.Rst,"ID_PAREXA02"
    Txn.Add Detalle_PAREXA03_grq.Rst,";RELA_PAREXA02"
 
    GrialCont.Apply Txn

2.- CABECERA + DETALLE + Detalle Extra

    Dim Cabecera_EXACDA01_grq as New GrialQuery
    Dim Detalle_EXACDA03_grq as New GrialQuery
    Dim Detalle_EXACDA04_grq as New GrialQuery
    ...
 
    Dim Txn As New GrialTransaction
 
    Txn.Add Cabecera_EXACDA02_grq.Rst,"Name=CabeceraGeneral: ID_EXACDA01"
 
    ' Este detalle toma el header por default 
    ' (recordset en el CMD anterior)
    Txn.Add Detalle_EXACDA03_grq.Rst,";RELA_EXACDA01"
 
    ' Este detalle toma el ID del item "CabeceraGeneral"
    Txn.Add Detalle_EXACDA04_grq.Rst,"Header=CabeceraGeneral: ;RELA_EXACDA01"
 
    Txn.Apply GrialCont


3.- CABECERA, DETALLE + Relación

    Dim Tabla_REACDO12_grq as New GrialQuery
    Dim Cabecera_EXACDA01_grq as New GrialQuery
    Dim Detalle_EXACDA03_grq as New GrialQuery
    ...
 
    Dim Txn As New GrialTransaction
 
    Txn.Add Tabla_REACDO12_grq.Rst,"Name=TablaDescripciones:ID_REACDO12"
    Txn.Add Cabecera_EXACDA02_grq.Rst,"ID_EXACDA01"
 
    ' Este detalle toma el header por default (recordset en el CMD anterior) 
    'y además actualiza un rela al primer recordset de la transacción
    Txn.Add Detalle_EXACDA03_grq.Rst, "RelaField=RELA_REACDO12/TablaDescripciones: ;RELA_EXACDA01"
 
    GrialCont.Apply Txn

Nota de Compatibilidad, Objeto SqlQuery

Existe también un Objeto SqlQuery que pertenece a una versión anterior del Framework y se mantiene por compatibilidad con los módulos que aún lo utilizan. Posee las mismas funciones y parámetros del objeto GrialTransaction, con ciertas diferencias: En lugar de Txn.Add, en el objeto SqlQuery se utiliza SqlQuery.Cmd, y en lugar de Txn.Apply, en el objeto SqlQuery se utiliza SqlQuery.UpdateRecords. También se mantiene para facilitar la compatibilidad un método Txn.Cmd sinónimo de Txn.Add

Sintaxis para ejecución de Stored Procedures

El GrialDataServer provee una sintaxis extendida para ejecutar Stored Procedures en el servidor de Base de Datos, que incluye la posibilidad de recuperar parámetros de output o Input/Output.

La sintaxis es la siguiente

  Txn.Cmd "Execute: procedure_name;param;param..."

Donde :

procedure_name: Es el nombre del Stored Procedure en el servidor de datos.

y cada "param" es un parámetro de dicho SP con la sigiente sintaxis:

"IOType:Name[=Value][:DataType][:Size]"

Donde:

  • IOType = puede ser: IO u O, donde IO=Input-output y O=Output
  • Name = nombre a asignar al campo del Rst con los resultados
  • Value = valor inicial para el parametro (solo para IOtype=IO)
  • DataType = puede ser: Number , Varchar, String o Date. (“String” es equivalente a “Varchar”)

Para parámetros de input, sólo es necesario colocar el valor del Parámetro. Si el valor que se especifica es alfanumérico debe encerrarse entre comillas dobles o simples, "" o , con lo que se asume que el parámetro es de tipo "Varchar2"

Si se omite "datatype", se determina el tipo del parámetro ("Number" o "Varchar") según el resultado de la función IsNumeric(Value). Esto último debe tenerse muy en cuenta si no se sabe bien que tipo de valores se pasarán en un parámetro alfanumérico. Es aconsejable especificar siempre "DataType" como "Varchar", o encerrrar el valor entre comillas, cuando se tiene un parámetro alfanumérico definido en el Stored Procedure.

Por ejemplo:

Tenemos en el servidor de datos un Stored Procedure :

Procedure Prueba_Ejemplo ( Param1 in Varchar2
                           ,Param2 in  Number
                           ,Param3 in out Varchar2
                           ,Param4 in out Number
                           ,Param5 out Varchar2
                           ,ParamFecha IN Date ) 
is
Begin
  Param3:= substr(Param1,1,2);
  Param4:= Param2 + 10;
  Param5:= to_char(ParamFecha,'mmm');
End;


y lo llamamos desde el módulo:

Dim Grq as New [[GrialQuery]]
Grq.Init "Execute:Prueba_Ejemplo; 'UNO'; 2; IO:Param3=1024:Varchar; " & _
          "IO:Param4=2003; O:Param5; " & DateParam(Now) 
Grialcont.LoadData Grq

En esta llamada:

  • el primer parametro es de tipo varchar, con valor "UNO"
  • el segundo parametro es de tipo number con valor 2
  • el tercer parametro es de entrada/salida (IO), su nombre es "Param3", valor de entrada "1024" y su tipo "Varchar2"
  • el cuarto parametro es de entrada/salida (IO), su nombre es "Param4", valor de entrada 2003 y su tipo "Number" (por ser el valor asignado un numero)
  • el quinto parametro es de salida (O), su nombre es "Param5"
  • el sexto parametro es de tipo "Date" y su valor inicial es la fecha y hora actuales

Nota: La función "DateParam(Fecha)" (componente del GrialUtilP), formatea el parámetro de tipo fecha según el standard esperado por el Grial Data Server (formato: "yyyy-mm-dd HH.nn.ss").

Luego de la ejecución del comando, se devuelve como resultado un recordset con tantos campos como parámetros de tipo OUTPUT/IO se hallan especificado. Los nombres de los campos son los indicados mediante el codigo "name" en la especificación de parámetros.

Luego de la ejecución (LoadData), Grq.Rst tendrá un solo registro con los siguientes campos:

? Grq.Rst!Param3.Value 
  UN

? Grq.Rst!Param4.Value
  12

? Grq.Rst!Param5.Value
  mar

Donde cada valor será aquel que el SP haya establecido durante su ejecución para cada parámetro de OUTPUT/IO.

Utilizando nuevos IDs de la misma transacción

Es posible utilizar dentro de una transacción, un valor de nuevo ID calculado por la base de datos correspondiente a un alta realizada en un ítem previo de la misma transacción. Esto se realiza colocando la macro: [Last_ID] en cualquier lugar del comando, esta macro será reemplazada por el ultimo valor de ID dado de alta en el ítem de la transacción especificado. Por default la referencia es al ítem de la transacción inmediatamente superior, pero puede modificarse la referencia utilizando las propiedades Name= y Header= del parámetro secundario del método Cmd.

Por Ejemplo:

  Case BUTTON_NEW

       PreEjec10_grq.PrepareAddNew
       CargarRegistroNuevoPreventivo
       Txn.Cmd PreEjec10_grq.Rst, "Name=Header_preventivo:ID_PREEJEC10"
       Txn.Cmd PreEjec11_grq.Rst, "Name=PE11:ID_PREEJEC11;RELA_PREEJEC10"
                   
       Txn.Cmd "Execute: PREEJEC10_IMPUTAR;[Last_ID]", "Header=Header_preventivo"


En este ejemplo, el procedimiento PREEJEC10_IMPUTAR tiene un solo parámetro de entrada, el cual será el ID del registro dado de alta en el ítem 0 (Name=Header_Preventivo) de la transacción.

El reemplazo de la macro [Last_ID] funciona en cualquier comando de texto que se envíe en una transacción, sean comandos SQL directos (Select,update,ect) o llamadas a procedimientos de la base.

Recuperar el Nuevo ID generado

Una vez aplicada la transaccion, se puede utilizar la function NewIDValue para recuperar el Nuevo ID generado (si es ALTA)

NuevoID = Txn.NewIDValue()

Por default NewIDValue() retorna el ID generado para el primer item de la transacción, por default: la cabecera.

Para obtener el Nuevo ID de otro item de la transacción, se debe indicar como parámetro el indice del item. Se recomienda asociar un nombre (Name=xx) al item y utilizar la funcion ItemIndex para obtener el indice, en lugar de indicar un indice numerico.

NuevoID = Txn.NewIDValue( Txn.ItemIndex("PE11") )



GrialQuery <<< >>> GrialCombo

Herramientas personales