versión 11.2 (Modificado)
Un trigger es un método asociado a una tabla. Es una propiedad de una tabla. Usted no llama a los triggers; los triggers son llamados automáticamente por el motor de 4D cada vez que manipula registros de la tabla (adición, eliminación, modificación, y carga). Puede escribir triggers muy simples, y luego volverlos más sofisticados.
Los triggers pueden evitar operaciones "ilegales" en los registros de su base. Son una herramienta muy poderosa que permite controlar las operaciones en tablas, como también evitar perdidas de datos accidentales. Por ejemplo, en un sistema de facturación, puede evitar que un usuario cree una factura sin especificar el cliente al que debe facturarse.
Activar y crear un trigger
Por defecto, cuando crea una tabla en el entorno Diseño, la tabla no tiene trigger.
Para utilizar un trigger para una tabla, necesita:
Activar el trigger e indicar a 4D cuando llamarlo.
Escribir el código para el trigger.
Activar un trigger que no está escrito o escribir un trigger sin activarlo no afecta las operaciones efectuadas en una tabla.
1. Activar un Trigger
Para activar un trigger, seleccione las opciones Triggers para la tabla en la ventana de propiedades de la tabla:
Al guardar un registro nuevo
Si esta opción se selecciona, el trigger se llamará cada vez que un registro se cree en la tabla, es decir en las siguientes circunstancias:
Cuando se añade un registro en la entrada de datos (entorno Diseño, comando ADD RECORD o comando SQL INSERT).
Cuando se crea y guarda un registro con CREATE RECORD y SAVE RECORD. Note que el trigger se llama en el momento en que llama SAVE RECORD, no cuando se crea.
Cuando se importan registros (entorno Diseño o utilizando un comando de importación).
Cuando se llaman otros comandos que crean y/o guardan nuevos registros (por ejemplo, ARRAY TO SELECTION, SAVE RELATED ONE, etc.).
Cuando se utiliza un plug-in que llama los comandos CREATE RECORD y SAVE RECORD.
Al guardar un registro existente
Si se selecciona esta opción, el trigger se llamará cada vez que se modifique un registro de la tabla, es decir en las siguientes circunstancias:
Cuando se modifica un registro en la entrada de datos (entorno Diseño, comando MODIFY RECORD o el comando SQL UPDATE).
Cuando se guarda un registro existente utilizando SAVE RECORD.
Cuando se llama un comando que guarda registros existentes (por ejemplo, ARRAY TO SELECTION, APPLY TO SELECTION, etc.).
Cuando se utiliza un plug-in que llama al comando SAVE RECORD.
Al borrar un registro
Si selecciona esta opción, el trigger se llamará cada vez que se borre un registro de la tabla, es decir en las siguientes circunstancias:
Cuando se borra un registro (entorno Diseño o llamando DELETE RECORD o DELETE SELECTION, o el comando SQL DELETE).
Cuando se efectúan operaciones que provocan la eliminación de un registro relacionado por intermedio de las opciones de control de eliminación de una relación.
Cuando se utiliza un plug-in que llama al comando DELETE RECORD.
Nota: El comando TRUNCATE TABLE no llama al trigger.
2. Crear un trigger
Para crear un trigger para una tabla, utilice la ventana de propiedades de la tabla, haga clic en el botón Editar o presione Alt (en Windows) u Opción (Macintosh) y doble clic en la tabla en la ventana de estructura. Para mayor información, consulte el manual de Diseño de 4D.
Eventos de base
Un trigger puede ser llamado por uno de los cuatro eventos de base descritos anteriormente. En el trigger, puede detectar qué evento está ocurriendo llamando la función Database event. Esta función devuelve un valor numérico que indica el evento de base.
Generalmente, usted escribe un trigger con una estructura de tipo Case of sobre el resultado devuelto por Database event. Puede utilizar las constantes del tema Database Events:
` Trigger for [unaTabla] C_LONGINT($0) $0:=0 ` Asume que la petición será aceptada Case of : (Database event=On Saving New Record Event) ` Realizar las acciones apropiadas para guardar el nuevo registro creado : (Database event=On Saving Existing Record Event) ` Realizar las acciones apropiadas para guardar un registro existente : (Database event=On Deleting Record Event) ` Realizar las acciones apropiadas para borrar un registro End case
Los triggers son funciones
Un trigger tiene dos propósitos:
Efectuar acciones sobre el registro justo antes de que se guarde o borre, o justo después de ser cargado.
Aceptar o rechazar una operación de base de datos.
1. Efectuar las acciones
Cada vez que se guarda un registro (añadido o modificado) a una tabla [Documentos], usted quiere "marcar" el registro con los marcadores de creación y modificación. Puede escribir el siguiente trigger:
` Trigger para tabla [Documentos] Case of : (Database event=On Saving New Record Event) [Documentos]Creacion_marca:=Time stamp [Documentos]Modificacion_marca:=Time stamp : (Database event=On Saving Existing Record Event) [Documentos]Modificacion_marca:=Time stamp End case
Nota: la función Time stamp utilizada en este ejemplo es un pequeño método de proyecto que devuelve el número de segundos transcurridos desde una fecha elegida arbitrariamente.
Una vez este trigger ha sido escrito y activado, no importa de que manera añada o modifique un registro en la tabla de la tabla [Documentos] (entrada de datos, importación, método de proyecto, plug-in 4D), los campos [Documentos]Creacion_marca y [Documentos]Modificacion_marca serán asignados automáticamente por el trigger antes de que el registro se escriba en el disco.
Nota: ver el ejemplo del comando GET DOCUMENT PROPERTIES para un análisis completo de este ejemplo.
2. Aceptar o rechazar la operación de una base
Para aceptar o rechazar una operación de la base, el trigger debe devolver un código de error de trigger en el resultado de la función $0.
Ejemplo
Tomemos el caso de una tabla [Empleados]. Durante la entrada de datos, usted controla el campo [Empleados]Numero_Seguridad_Social. Cuando el usuario hace clic en el botón de validación, usted verifica el campo utilizando el método de objeto del botón:
` Método de objeto bAccept If (Numero Valido ([Empleados]Numero_Seguridad_Social)) ACCEPT Else BEEP ALERT ("Introduzca un número de seguridad social y haga clic de nuevo en OK.") End if
Si el valor del campo es correcto, acepta la entrada de datos; si el valor del campo no es correcto, muestra una alerta y permanece en entrada de datos.
Si también crea registros para la tabla [Empleados] por programación, el siguiente código sería válido pero violaría la regla expresada en el método de objeto creado anteriormente:
` Extracción de un método de proyecto ` ... CREATE RECORD ([Empleados]) [Empleados]Nombre :="DOE" SAVE RECORD ([Empleados]) `¡Violación de la regla! El número de seguridad social no ha sido asignado ` ...
Utilizando un trigger para la tabla [Empleados], puede implementar la regla [Empleados]Numero_Seguridad_Social en todos los niveles de la base. El trigger se vería así:
` Trigger for [Empleados
] $0:=0 $dbEvent:=Database event Case of : (($dbEvent=On Saving New Record Event) | ($dbEvent=On Saving Existing Record Event)) If (Not(Numero Valido ([Empleados
]Numero_Seguridad_Social
))) $0:=-15050 Else ` ... End if ` ... End case
Una vez este trigger está escrito y activado, la línea SAVE RECORD ([Empleados]) generará un error de base -15050, y el registro NO se guardará.
De la misma forma, si un plug-in 4D intenta guardar un registro en [Empleados] con un número de seguridad social incorrecto, el trigger generará el mismo error y el registro no se guardará.
El trigger garantiza que nadie (usuario, desarrollador, plug-in, 4D Open client con 4D Server) pueda violar la regla del número de seguridad social, bien sea deliberada o accidentalmente.
Note que incluso si no tiene un trigger para una tabla, la base puede devolver errores cuando se trata de guardar o borrar un registro. Por ejemplo, si intenta guardar un registro con un valor duplicado en un campo indexado único, se devuelve el error -9998.
Los triggers devuelven nuevos tipos de errores en 4D:
4D administra los errores "normales": índice único, control de datos relacionales, etc.
Utilizando triggers, puede crear códigos de errores únicos para su aplicación.
Importante: puede devolver el código de error de su elección. Sin embargo, NO utilice códigos de error utilizados por el motor de 4D. Recomendamos utilizar códigos de error entre -32 000 y -15 000. Nos reservamos los errores superiores a -15 000 para el motor de 4D.
A nivel del proceso, usted administra los errores trigger de la misma manera que los errores de motor de base de datos:
Puede permitir a 4D mostrar la caja de diálogo de error estándar, luego se interrumpe el método.
Puede utilizar un método de gestión de errores instalado utilizando ON ERR CALL y recuperar el error de la manera apropiada.
Notas:
Durante la entrada de datos, si un error trigger es devuelto mientras intenta validar o borrar un registro, el error se trata como un error de índice único. La caja de diálogo de error se muestra, y permanece en la entrada de datos. Incluso si utiliza una base en el entorno Diseño (no en el entorno Aplicación), usted se beneficia del uso de triggers.
Cuando se genera un error por un trigger en el marco de un comando que actúa sobre una selección de registros (como DELETE SELECTION), la ejecución del comando se detiene inmediatamente, sin que la selección haya sido procesada completamente. Este caso requiere una gestión apropiada por parte del desarrollador, basada, por ejemplo, en la conservación temporal de la selección, el procesamiento y la eliminación del error antes de la ejecución del trigger, etc.
Incluso cuando un trigger no devuelve un error ($0:=0), esto no significa que una operación de la base será exitosapuede ocurrir una violación de índice único. Si la operación es la actualización de un registro, el registro puede estar bloqueado, se puede producir un error de entrada/salida puede ocurrir, etc. Estas verificaciones son efectuadas después de la ejecución del trigger. Sin embargo, desde el punto de vista del nivel superior del proceso en ejecución, los errores devueltos por el motor de la base de datos o por un trigger son de la misma naturalezaun error trigger es un error del motor de la base de datos.
Triggers y la arquitectura 4D
Los triggers funcionan al nivel del motor de la base de datos. Este punto se resume en el siguiente diagrama:
Los triggers se ejecutan en el equipo donde está el motor de la base de datos. Esto es evidente en el caso de 4D versión mono usuario. En 4D Server, los triggers se ejecutan en el equipo servidor (en el proceso activo) y no en el equipo cliente.
Cuando se llama un trigger, se ejecuta dentro del contexto del proceso de base de datos que intenta la operación. Este proceso, invoca la ejecución del trigger y se llama proceso llamante.
Los elementos incluidos en este contexto difieren si la base se ejecuta con 4D en modo local o con 4D Server:
Con 4D en modo local, el trigger funciona con las selecciones actuales, registros actuales, estados de lectura/escritura de las tablas, operaciones de bloqueos de registros, etc., del proceso llamante.
Con 4D Server, sólo el contexto de base de datos del proceso cliente llamante se conserva (bloqueo de registros, estados de lectura/escritura, etc.). 4D Server igualmente garantiza que el registro actual de la tabla del trigger esté correctamente posicionado. Los otros elementos contextuales (selecciones actuales por ejemplo) son las del proceso del trigger.
Tenga cuidado en utilizar otra base de datos u objetos del lenguaje del entorno 4D, porque un trigger podría ejecutarse en una maquina diferente de la del proceso que lo llama ¡este es el caso con 4D Server!
Variables interproceso: un trigger tiene acceso a las variables interproceso del equipo donde se ejecuta. Con 4D Server, puede acceder a una maquina diferente a la del proceso llamante.
Variables proceso: cada trigger tiene su propia tabla de variables proceso. Un trigger no tiene acceso a las variables proceso del proceso llamante.
Variables locales: puede utilizar las variables locales en un trigger. Su alcance es la ejecución del trigger; se crean/eliminan en cada ejecución.
Semáforos: un trigger puede probar o fijar semáforos globales y locales (en el equipo donde se ejecuta). Sin embargo, un trigger debe ejecutar rápidamente, de manera que debe ser muy cuidadoso cuando pruebe o defina semáforos dentro de triggers.
Conjuntos y selecciones temporales: si utiliza un conjunto o una selección temporal en un trigger, trabaja en el equipo donde los triggers se ejecutan.
Interfaz del usuario: NO utilice elementos de la interfaz del usuario en un trigger (alertas, mensajes o cajas de diálogo). De la misma forma, debe limitar todo seguimiento de triggers en la ventana del Depurador. Recuerde que en Cliente/Servidor, los triggers se ejecutan en el equipo 4D Server. Un mensaje de alerta en el equipo servidor no ayuda al usuario en un equipo cliente. Deje al proceso llamante administrar la interfaz del usuario.
Triggers y transacciones
Las transacciones deben ser administradas en el nivel del proceso llamante. No deben administrarse a nivel del trigger. Si durante la ejecución del trigger, tiene que añadir, modificar o borrar varios registros, primero debe utilizar el comando In transaction desde el trigger para probar si el proceso llamante está en transacción actualmente. Si no es el caso, el trigger podría encontrarse con un registro bloqueado. Por lo tanto, si el proceso llamante no está en transacción, no comienzan las operaciones en los registros y devuelve un error en $0 para indicar al proceso llamante que la operación de la base de datos debe ejecutarse en una transacción. Por otra parte, si encuentra registros bloqueados, el proceso llamante no podrá deshacer las acciones del trigger.
Nota: con el fin de optimizar el funcionamiento combinado de los triggers y transacciones, 4D no llama triggers después de la ejecución de VALIDATE TRANSACTION. Esto evita que los triggers se ejecuten dos veces.
Triggers en cascada
Dada la siguiente estructura de ejemplo:
Nota: las tablas han sido contraídas; tienen más campos de los que se muestran.
Supongamos que la base de datos "autoriza" la eliminación de una factura. Podemos examinar cómo sería tratada tal operación a nivel del trigger (porque también podría realizar eliminaciones a nivel del proceso).
Para conservar la integridad relacional de los datos, la eliminación de una factura requiere las siguientes acciones de parte del trigger de [Facturas]:
Disminuir el campo Ventas de la tabla [Clientes], en la cantidad de la factura.
Borrar todos los registros de [Linea_Factura] relacionados con la factura.
Esto también implica que el trigger de [Linea_Factura] disminuya el campo Cantidad vendida de los registros [Productos] relacionados con la línea de factura a eliminar.
Borrar todos los registros de [Pagos] relacionados con la factura borrada.
Primero, el trigger de [Facturas] debe efectuar estas acciones sólo si el proceso llamante está en transacción, de manera que sea posible deshacer en caso de encontrar un registro bloqueado.
Segundo, el trigger de [Linea_Factura] está en cascada con el trigger de [Facturas]. El trigger [Linea_Factura] se ejecuta dentro de la ejecución del trigger [Facturas], porque la eliminación de los elementos de la lista es consecutiva a una llamada a DELETE SELECTION desde el trigger de [Facturas].
Imagine que todas las tablas en este ejemplo tienen triggers activados para todos los eventos de la base de datos. La cascada de triggers será:
El trigger de [Facturas] se llama porque el proceso llamante borra una factura El trigger de [Clientes] se llama porque el trigger de [Facturas] trigger actualiza el campo Ventas_Brutas El trigger de [Linea_Factura] se llama porque el trigger [Facturas] borra una línea (repetida) El trigger de [Productos] se llama porque el trigger de [Linea_Factura] actualiza el campo Cantidad_Vendida El trigger de [Pagos] se llama porque el trigger de [Facturas] borra un pago (repetido)
En esta cascada, el trigger de [Facturas] se ejecuta en el nivel 1, los triggers de [Clientes], [Linea_Factura], y [Pagos] en el nivel 2 y el trigger de [Productos] en el nivel 3.
Desde dentro de los triggers, puede utilizar el comando Trigger level para detectar el nivel en el cual se ejecuta un trigger. Además, puede utilizar el comando TRIGGER PROPERTIES para obtener información sobre los otros niveles.
Por ejemplo, si borra un registro de [Productos] a nivel del proceso, el trigger de [Productos] se ejecutará en el nivel 1, no en el nivel 3.
Con Trigger level y TRIGGER PROPERTIES, puede identificar la causa de una acción. En nuestro ejemplo, una factura se borra al nivel del proceso. Si borramos un registro de [Clientes] a nivel del proceso, el trigger de [Clientes] debe intentar borrar todas las facturas relacionadas con ese cliente. Esto significa que el trigger [Facturas] será llamado como se llamó anteriormente, pero por otra razón. Desde el trigger de [Facturas], puede detectar si se ejecuta en el nivel 1 ó 2. Si se ejecutó en el nivel 2, puede verificar si fue porque se borro el registro de [Clientes]. Si este es el caso, no tiene que preocuparse en actualizar el campo Ventas_Brutas.
Utilización de la numeración automática en un trigger
Cuando manipula el evento de base On Saving New Record Event, puede llamar el comando Sequence number para mantener un número de identificación único para los registros de una tabla.
Ejemplo
` Trigger for table [Facturas] Case of : (Database event=On Saving New Record Event) ` ... [Facturas]Numero_Identificacion_Factura:=Sequence number ([Facturas]) ` ... End case
Ver también
Database event, Métodos, Record number, Trigger level, TRIGGER PROPERTIES.