Quisiera saber si es posible que me expliques con uno o dos ejemplos una rutina para controlar los errores que se presentan cuando se utilizan los desencadenantes (integridad referencial). La verdad es que no tengo mucha experiencia en el manejo del vfp 9.0 y te agradecería que me aconsejaras cual es la mejor opción.
Bueno para comenzar en Visual FoxPro y en cualquier otro gestor de base de datos los errores que se producen cuando falla el desencadenante se deben a estas situaciones que son las más comunes: 1. Estás insertando un registro en la tabla secundaria con un valor clave que no existe en la tabla primaria (aquí está restringida la inserción y por lo tanto es un error de inserción). 2. Estás actualizando en la tabla primaria el valor clave de un registro que tiene registros relacionados en la tabla secundaria (aquí está restringida la actualización, y por lo tanto es un error de actualización, ésta solo podrá realizarse cuando en la tabla secundaria no existan registros relacionados tanto física como lógicamente). 3. Estás eliminando en la tabla primaria un registro que tiene registros relacionados en la tabla secundaria (aquí está restringida la eliminación, y por lo tanto es un error de eliminación, ésta solo podrá realizarse cuando en la tabla secundaria no existan registros relacionados tanto física como lógicamente). En Visual FoxPro cuando falla el desencadenante se produce el error número 1539, una vez que se haya notificado que se ha producido este tipo de error, usted deberá llamar a la función Aerror() que crea una matriz de variables de memoria con información relativa al error más reciente de Visual FoxPro u ODBC. El elemento número 5 de la matriz, si ha fallado un desencadenante (error 1539), contiene uno de los siguientes valores numéricos: 1 - El desencadenante Insert falló (inserción). 2 - El desencadenante Update falló (actualización). 3 - El desencadenante Delete falló (eliminación). Para poder controlar este tipo de errores la rutina más común es esta: En el evento click de un botón de comando o en el evento de un formulario que sea para guardar cambios se escribe un código parecido a este: Local lcError, lcArrayError[AERRORARRAY] lcError = !Tableupdate(.T.) If lcError Then If Aerror(lcArrayError) > 0 Thisform.Error(lcArrayError[1]) Endif Else Go (Recno()) && Forzar la actualización de cualquier relación. Endif Return !lcError Para el caso de que sea u formulario de uno a varios, deberá iniciar una transacción para actualizar todas las tablas a las que se le hayan hecho cambios y en el caso de que en alguna de ellas falle la actualización ya sea por una falla de desencadenante o cualquier otro tipo de error, entonces deberá revertir los cambios con Rollback, por ejemplo en el siguiente código se actualiza la tabla primaria y luego se actualizan las tablas secundarias las cuales están almacenados sus nombres en una matriz personalizada, este código es ideal para formularios de tipo factura o formularios de introducción de datos de uno a varios, este código va en un evento personalizado de un formulario: Local lcError, lcArrayError[AERRORARRAY] Begin Transaction lcError = (Txnlevel() = 0) If !lcError If !lcError Then * Si no han cambiado los datos en la tabla primaria, no se disparará * el desencadenante a menos que lo forcemos. Select (This.ParentTable) If GetFldState(-1) = Replicate("1", Fcount() + 1) =SetFldState(2,2) EndIf lcError = !Tableupdate(.T.) && Actualizar tabla primaria. If !lcError For i = 1 To Alen(This.AChildTables, 1) Select (This.AChildTables(i,1)) If GetNextModified(0, (This.AChildTables(i,1))) <> 0 lcError = !Tableupdate(.T.) Endif If lcError Exit EndIf EndFor Endif If !lcError Then End Transaction Select (This.ParentTable) Else RollBack =Aerror(lcArrayError) This.Error(lcArrayError[1], lcArrayError[2]) This.RefreshForm() EndIf EndIf EndIf Return !lcError Ahora para responder a tu pregunta y con un ejemplo específico te explicaré cómo se tratan los errores producidos por desencadenantes, supongamos que tenemos un formulario de facturación en el cual tiene las tablas respectivas como Clientes, encabezado_factura, detalle_factura, vendedor, etc, debidamente relacionadas y con la integridad referencial establacida, se debe ingresar el NIT del cliente en la tabla encabezado_factura, pero teniendo en cuanta que dicha tabla no registra el NIT de un cliente que no esté registrado en la tabla clientes, entonces se procederá a dar una solución ya sea registrando el respectivo cliente o verificando los datos del mismo así: En el evento click de un botón guardar iría un código como el siguiente: Local lcError, lcArrayError[AERRORARRAY] Begin Transaction lcError = (Txnlevel() = 0) If !lcError If !lcError Then * Si no han cambiado los datos en la tabla primaria, no se disparará * el desencadenante a menos que lo forcemos. If Alias() <> "FACTURA_ENCABEZADO" Select Factura_encabezado Endif If GetFldState(-1) = Replicate("1", Fcount() + 1) =SetFldState(2,2) EndIf lcError = !Tableupdate(.T.) && Actualizar tabla primaria. If !lcError Select Detalle_factura If GetNextModified(0, "Detalle_factura") <> 0 lcError = !Tableupdate(.T.) Endif If lcError Exit EndIf Endif If !lcError Then End Transaction Select Select Factura_encabezado Else RollBack =Aerror(lcArrayError) Thisform.Error(lcArrayError[1], lcArrayError[2]) Thisform. Refresh() EndIf EndIf EndIf Return !lcError En el caso de que el usuario intentó ingresar el NIT de un cliente que no está registrado en la tabla clientes, entonces esto se resuelve así: En el evento Error del Formulario escribiríamos un código cómo el siguiente: =AError(lcAerror) Do Case Case nError = 1539 && Falló el desencadenante en este caso el desencadenante Insert. If MessageBox("El cliente no existe. ¿Desea registrarlo?, 48, "Error") = 6 && Sí If lcAerror(5) = 1 && Falló el desencadenante Insert. This.RegistrarCliente() && Un evento para registrar el cliente. EndIf Else This.TxtNitCliente.Value = "" && Si el usuario se equivocó entonces corrige el error. Endif Case nError = 1582 Resolver el problema Case nError = .... y así para resolver otros errores Resolver el problema EndCase Con esto espero haber sido claro de cómo se resuelve estos errores de desencadenantes. Nota: si se hace una aplicación que se conecta a otras bases de datos, es decir, mediante ODBC, debes consultar los códigos de error de los desencadenantes en la respectiva documnetación de la base de datos de origen para reemplazar los códigos de error por sus respectivos valores.