Jump to content


Photo

[RESUELTO] Capturando Eventos de Firebird desde Delphi


  • Please log in to reply
26 replies to this topic

#1 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 09 April 2010 - 12:03 PM

Hola

Estoy desarrollando un sistema donde tengo que disparar procesos dependiendo de registros agregados a una tabla desde procesos diferentes, es decir, un proceso agrega los registros y otro se encarga de disparar los procesos.

Pues bien, la historia comenzó cuando utilizaba Paradox.

Mi primer idea de hacer esto (hace unos 10 años) fué la de leer periódicamente la tabla y al encontrar nuevos registros ejecutaba los procesos correspondientes.

Posteriormente utilicé sockets para enviar la orden de un programa a otro incluso utilizando ya Firebird.

Cualquiera de estas formas me funcionó en su momento, sin embargo, seguía inconforme con la forma de hacerlo. Hace unos días y aunque parezca de risa, me levanté a media noche con una idea, si Firebird puede generar eventos y Delphi a través de su componente IBEvents los puede capturar, tendría que haber una forma de hacer lo que quiero.

Pues bien, después de unos días encontré la forma de hacerlo y quiero compartir con ustedes mi idea, por supuesto y como siempre lo he dicho, habrá mejores alternativas y me gustaría que esto que he desarrollado fuese mejorado con optimización de código u otras alternativas.

Lo primero que hice fué generar el Evento en Firebird.



sql
  1. /*****************************************************************/
  2. /*    Following SET SQL DIALECT is just for the Database Comparer        */
  3. /*****************************************************************/
  4. SET SQL DIALECT 3;
  5.  
  6.  
  7. SET TERM ^ ;
  8.  
  9. CREATE OR ALTER TRIGGER "POST_EVENT" FOR EVENTOS
  10. ACTIVE AFTER INSERT POSITION 0
  11. AS
  12. BEGIN
  13.   IF (NEW.event = 1) THEN
  14.       POST_EVENT 'NEW_EMAIL';
  15.   IF (NEW.event = 2) THEN
  16.       POST_EVENT 'NEW_MESSAGE';
  17.   IF (NEW.event = 3) THEN
  18.       POST_EVENT 'NEW_GREETING';
  19.   IF (NEW.event = 4) THEN
  20.       POST_EVENT 'NEW_PHONE_NOTIFY'';
  21. end
  22. ^
  23.  
  24. SET TERM ; ^



new.event es un campo de la base de datos el cual contiene un ID para determinar el evento que se va a generar.

Bueno pues la tarea siguiente era codificar la captura de estos eventos en Delphi, para ello utilicé el componente IBEvents de la paleta IBX.

Primero se declaran los eventos.



delphi
  1. procedure TfrmPMSNec.FormCreate(Sender: TObject);
  2. begin
  3.   IBDatabase1.Connected := true;
  4.   IBEvents1.Events.Add('NEW_EMAIL');
  5.   IBEvents1.Events.Add('NEW_MESSAGE');
  6.   IBEvents1.Events.Add('NEW_GREETING');
  7.   IBEvents1.Events.Add('NEW_PHONE_NOTIFY');
  8.   IBEvents1.RegisterEvents;
  9. end;



Y en el evento EventAlert del componente IBEvents disparo los procesos correspondientes a cada una de las acciones.



delphi
  1. procedure TfrmPMSNec.IBEvents1EventAlert(Sender: TObject; EventName: string;
  2.   EventCount: Integer; var CancelAlerts: Boolean);
  3. begin
  4.   if EventName = 'NEW_EMAIL' then
  5.   begin
  6.     // Disparo proceso de nuevo correo
  7.   end;
  8.   if EventName = 'NEW_MESSAGE' then
  9.   begin
  10.     // Disparo proceso de nuevo Mensaje
  11.   end;
  12.   if EventName = 'NEW_GREETING' then
  13.   begin
  14.     // Disparo proceso de nuevo Saludo
  15.   end;
  16.   if EventName = 'NEW_PHONE_NOTIFY' then
  17.   begin
  18.     // Disparo proceso de nueva notificación a teléfono
  19.   end;
  20. end;



Con esto, ya no me preocupo por buscar periódicamente en la tabla por nuevos eventos ni de estar enviando a través de sockets la órden para ejecutar los procesos.

Espero que sea de ayuda y si hay algún comentario para mejorar y optimizar esta idea será bienvenida.  :smiley:

Salud OS
  • 0

#2 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 09 April 2010 - 12:20 PM

Esa es una de las cosas que me gusta de Firebird, el uso de eventos.
Para complementar los dichos de Eliseo, si me lo permite, recomiendo la lectura del paper The Power of Firebird Events, de Milan Babuskov (disculpen el error en el apellido... no se cómo poner la s con la v encima) durante Firebird Conference Prague 2005.
Se da una descripción bastante completa sobre los eventos y unas consideraciones muy importantes a tener en cuenta.

EDITO:
Y aquí hay que reconocer una ventaja de FlameRobin por sobre IBExpert (en su versión Personal): posee un monitor de eventos bastante intuitivo y sencillo.

Saludos,

  • 0

#3 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2092 posts
  • LocationRepública Dominicana

Posted 09 April 2010 - 12:24 PM

Saludos.

Una pregunta que me llega de momento: ¿El tipo de Evento puede ser modificado?.

Siendo cierta, entonces debes de proceder a cambiar tu Trigger a un polivalente INSERT OR UPDATE.  De pronto es lo que se me ocurre, puesto que el código en Delphi se ve correcto.
  • 0

#4 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 09 April 2010 - 12:39 PM

Saludos.

Una pregunta que me llega de momento: ¿El tipo de Evento puede ser modificado?.

Siendo cierta, entonces debes de proceder a cambiar tu Trigger a un polivalente INSERT OR UPDATE.  De pronto es lo que se me ocurre, puesto que el código en Delphi se ve correcto.


No considero la actualización de los eventos solo me interesan los eventos nuevos, por eso es que solo uso ON INSERT, sin embargo si actualizo un campo status del evento para asignarlo como procesado.

Salud OS
  • 0

#5 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 09 April 2010 - 12:45 PM

Yo tengo una duda... ¿Firebird te ha dejado nombrar al trigger como POST_EVENT? Porque POST_EVENT es la "orden" para lanzar un evento. Yo nombraría al trigger de otro modo para evitar confusiones y cualquier inconveniente.

Saludos,
  • 0

#6 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 09 April 2010 - 12:48 PM

No, es que lo modifique amigo, me falto la O jajajajajaja

ya lo corrijo.

Aunque si te deja poner el nombre que quieras.



sql
  1. CREATE OR ALTER TRIGGER "POST_EVENT" FOR EXTENSIONES
  2. ACTIVE AFTER INSERT POSITION 0
  3. AS
  4. BEGIN
  5.   /* Trigger text */
  6. END



Salud OS
  • 0

#7 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 09 April 2010 - 12:58 PM

Vaya sorpresa,
Como yo tengo la costumbre de tener una nomenclatura un tanto ya estandarizada para nombrar a los elementos (triggers, SP, índices, etc) me evito el "probar" si Firebird protesta.

Saludos,
  • 0

#8 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 09 April 2010 - 01:00 PM

Vaya sorpresa,
Como yo tengo la costumbre de tener una nomenclatura un tanto ya estandarizada para nombrar a los elementos (triggers, SP, índices, etc) me evito el "probar" si Firebird protesta.

Saludos,


Claro amigo, entiendo tu punto y se agradece, son los errores que suelo cometer al ser un empírico  :embarrassed:

Salud OS
  • 0

#9 razadi

razadi

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 681 posts
  • LocationMéxico D.F.

Posted 18 August 2010 - 05:11 PM

Gracias egostar por tan ilustrativa muestra del uso de eventos en FireBird, actualmente estoy usando dicho código, pero ahora me salta un problema  :( :(

Al momento de ejecutar desde DELPHI un procedimiento para ver cuantos registros tengo en la tabla a la que se le inserto un registro me encuentro con la sorpresa que no me actualiza el último registro precisamente el que acabo de insertar, es decir...



delphi
  1. procedure TForm1.ZIBEventAlerter1EventAlert(Sender: TObject; EventName: string;
  2.   EventCount: Integer; var CancelAlerts: Boolean);
  3. var
  4.   sRefe,sSQL: string;
  5. begin
  6.   if EventName = 'NEW_REG' then begin
  7.   {contador sin valor}
  8.     Inc(iCuenta);
  9.   {Inserto en un memo para ver que cuando se ejecuta el evento}
  10.     Memo1.Lines.Add(IntToStr(EventCount)+' Se inserto un registro '+IntToStr(iCuenta));
  11.   {realizo esta consulta a la tabla afectada, con el trigger del POST_EVENT}
  12.     sSQL := 'SELECT DISTINCT SYS_REFE FROM SYS_LOG WHERE (SYS_OPER=''O'')';
  13.     with ZQuery1 do begin
  14.       Close; SQL.Clear; SQL.Add(sSQL); Open;
  15.       First;
  16.       while not Eof do begin
  17.         Memo2.Lines.Add(FieldByName('SYS_REFE').AsString);
  18.         Next;
  19.       end;
  20.       Close;
  21.     end;
  22.   end;
  23. end;



cuando tengo 4 registros e inserto el num 5 si se ejecuta bien el POST_EVENT pero el resultado de la consulta me arroja 4 en ves de 5, tengo que cerrar la conexión para que me vuelva a tomar los 5 pero si agrego el 6 pues sólo me mostrará 5 registros.

que tendré mal????  :

o de plano  8o|


  • 0

#10 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 18 August 2010 - 05:21 PM

En que momento disparas el evento ?

¿ En el BEFORE POST o en el AFTER POST ?

Salud OS
  • 0

#11 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1484 posts
  • LocationMallorca

Posted 18 August 2010 - 05:47 PM

Tu problema muy probablemente se debe a las transacciones. Los datos introducidos por una transacción solo son visibles después de que haya finalizado esa transacción, y además solo serán visibles para las nuevas transacciones que empiecen a partir de ese momento.

Así que o bien aún no ha finalizado la transacción que inserta los datos, o bien la transacción desde la que se calcula el total de registros ya estaba abierta anteriormente.

Eso, o como sugiere Egostar, estas utilizando el evento BEFORE POST, y por tanto los datos aún no han sido introducidos en la base de datos.
  • 0

#12 razadi

razadi

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 681 posts
  • LocationMéxico D.F.

Posted 18 August 2010 - 09:45 PM

En que momento disparas el evento ?

¿ En el BEFORE POST o en el AFTER POST ?

Salud OS


Lo hago en el After post, del trigger

Tu problema muy probablemente se debe a las transacciones. Los datos introducidos por una transacción solo son visibles después de que haya finalizado esa transacción, y además solo serán visibles para las nuevas transacciones que empiecen a partir de ese momento.

Así que o bien aún no ha finalizado la transacción que inserta los datos, o bien la transacción desde la que se calcula el total de registros ya estaba abierta anteriormente.

Eso, o como sugiere Egostar, estas utilizando el evento BEFORE POST, y por tanto los datos aún no han sido introducidos en la base de datos.


mmm omiti un detalle, lo estoy haciendo con ZEOS, lo mas probable es que tenga que ver las transacciones como dices Marc, dejen lo intento y les comento.

  • 0

#13 razadi

razadi

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 681 posts
  • LocationMéxico D.F.

Posted 19 August 2010 - 08:51 AM

Listo quedo resuelto, efectivamente Marc, son las transacciones, en ZEOS el componente TConnection tiene una propiedad TransactIsolationLevel, esto debe especificarse con el valor tiReadCommitted para que automáticamente realice el commit en cada transacción.

Gracias amigos. (b) (b) (b)
  • 0

#14 chelard

chelard

    Newbie

  • Miembros
  • Pip
  • 1 posts

Posted 01 September 2010 - 04:12 PM

Hola egostar:

agradeceria mucho si me indicas como puedo hacer lo mismo, pero con una base de datos postgresql 8.4

gracias anticipadamente.
  • 0

#15 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2092 posts
  • LocationRepública Dominicana

Posted 01 September 2010 - 05:44 PM

Hola egostar:

agradeceria mucho si me indicas como puedo hacer lo mismo, pero con una base de datos postgresql 8.4

gracias anticipadamente.


Saludos.

Con esa BD debes usar otros componentes y no el IbEvents que es nativo para Firebird/Interbase.

Puedes echarle un ojo a AnyDac en la sección Unified DB Events Support, también los PgDac o de los mismos autores UniDac.

P.D. No estoy seguro si alguno de los componentes que te menciono soportan dicha característica de esa BD.

Por cierto, Bienvenid@ chelard a DelphiAccess, espero sea de tu gusto!!!!
  • 0

#16 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 01 September 2010 - 05:49 PM

Hola egostar:

agradeceria mucho si me indicas como puedo hacer lo mismo, pero con una base de datos postgresql 8.4

gracias anticipadamente.


Hola Chelard bienvenido a DelphiAccess

Los eventos son capturados por un componente específico de Interbase/Firebird (IBEvents), por lo que desconozco si existe algún componente que capture los eventos de PostgreSQL.

Puedes ver esta página a ver si te sirve de algo.

Salud OS

PD. Vaya amigo Rolphy, me ganó la respuesta :)
  • 0

#17 enecumene

enecumene

    Webmaster

  • Administrador
  • 7419 posts
  • LocationRepública Dominicana

Posted 22 October 2012 - 10:22 AM

Reviso de nuevo este hilo porque ya necesitaré ese evento :D, tengo la duda existencial, aún no esto muy claro sobre el asunto, ¿Cómo hago cuando hay un registro nuevo?, si tengo un trigger que dispara un Generador, ¿cómo podría usarlo?.

Saludos.
  • 0

#18 casi

casi

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 191 posts

Posted 22 October 2012 - 01:30 PM

Hola, acabo de ver este hilo, aquí tengo un sencillo tutorial en español, escrito por una chica argentina.
http://www.intitec.c..._de_eventos.pdf



pd: ¿cómo pongo un enlace sin que se vea el mismo?, lo típico de "pinchando aquí" vas al enlace. Y al pinchar en "aquí" se enlace :D



  • 0

#19 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 22 October 2012 - 01:38 PM

Así amigo Casi :)

[nobbc]
  Pinche Aquí 
[/nobbc]

Pinche Aquí

Saludos :)
  • 0

#20 casi

casi

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 191 posts

Posted 22 October 2012 - 02:22 PM

Vaya, qué fácil, es lo malo de hacer las cosas con un botón, al igual que las calculadoras, se olvida uno hasta de multiplicar.
Gracias :)

  • 0




IP.Board spam blocked by CleanTalk.