Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Verwenden von Triggern für Firebird 2.5 DB (https://www.delphipraxis.net/159804-verwenden-von-triggern-fuer-firebird-2-5-db.html)

Frankdarwin 13. Apr 2011 14:17

Datenbank: Firebird • Version: 2.5 • Zugriff über: Interbase

Verwenden von Triggern für Firebird 2.5 DB
 
Hallo Spezialisten,
ich versuche gerade meine ertsen Erfolgserlebnisse mit einer DB Anwendung zu bekommen. Zu diesem Zweck habe ich mit IBExpert eine einfache FB DB erstellt. Die Tabellen enthalteen alle ein Feld namens ID für den PK. Darüber hinaus habe ich einen Trigger erstellt, der das Feld ID versorgen soll. Das funktioniert unter IBE einwandfrei.
Jetzt möchte ich um diese DB herum mit Delphi XE eine Anwendung zur Datenerfassung schreiben.
Ich kann Daten in allen Feldern und Tabellen erfassen. Nur bekomme ich jedesmal eine Meldung, dass das Feld ID einen Wert benötigt. Eigentlich sollte dieser von dem Trigger eingetragen werden. Jetzt kommt meine (für viele wahrscheinlich sehr einfache) Frage:

Was muss ich eigentlich in Delphi tun, damit ein Trigger aus der DB automatisch ausgeführt wird?

Ich habe sehr viel gesucht und gelesen. Auch in den Foren. Viele Themen behandeln das Thema Trigger. Leider wurde ich zu meiner Grundsatzfrage nicht fündig. Oder ich habe es einfach überlesen.

Ich würde mich über einen kleinen Nachhilfeunterricht in Form einer (oder mehrere) Antworten sehr freuen.

ThomasBab 13. Apr 2011 14:40

AW: Verwenden von Triggern für Firebird 2.5 DB
 
Hallo!

Bin zwar kein Spezialist, aber vielleicht kann ich ein wenig Licht ins Dunkle bringen:

Hier ein praktisches Beispiel (Auszugsweise):

Die Tabelle:
Code:
CREATE GENERATOR ID;

CREATE TABLE IPCAM (
    ID       BIGINT NOT NULL,
    IDCAM    BIGINT NOT NULL,
    ANGELEGT DATUMUHRZEIT DEFAULT current_timestamp /* DATUMUHRZEIT = TIMESTAMP */ NOT NULL /* DATUMUHRZEIT = TIMESTAMP */,
    BILD     BLOB SUB_TYPE 0 SEGMENT SIZE 16384
);

/******************************************************************************/
/*                                Primary Keys                               */
/******************************************************************************/

ALTER TABLE IPCAM ADD CONSTRAINT PK_IPCAM PRIMARY KEY (ID);


/******************************************************************************/
/*                                Foreign Keys                               */
/******************************************************************************/

ALTER TABLE IPCAM ADD CONSTRAINT FK_IPCAM_1 FOREIGN KEY (IDCAM) REFERENCES CAMTYP (ID);


/******************************************************************************/
/*                                  Indices                                  */
/******************************************************************************/

CREATE INDEX IPCAM_IDX1 ON IPCAM (ANGELEGT);


/******************************************************************************/
/*                                  Triggers                                 */
/******************************************************************************/


SET TERM ^ ;



/******************************************************************************/
/*                            Triggers for tables                            */
/******************************************************************************/



/* Trigger: IPCAM_BIU0 */
CREATE OR ALTER TRIGGER IPCAM_BIU0 FOR IPCAM
ACTIVE BEFORE INSERT OR UPDATE POSITION 0
AS
begin
    if (new.id is null) then
    new.id = gen_id(id, 1);
    if (new.angelegt is null) then
    new.angelegt = current_timestamp;
end
^


SET TERM ; ^
Hier der Generator:

Code:
CREATE SEQUENCE ID;
ALTER SEQUENCE ID RESTART WITH 619995;


Nun der Codeauszug, um Daten einzutragen bzw. ein Update auszuführen:

Delphi-Quellcode:
procedure Tccamera.Speichercamtyp;
var
  Sql: string;
begin
  try
    if CamTypName = '' then
    begin
      ShowMessage('Kein Kameratyp angegeben!');
      exit;
    end;
    if CamTypID <= 0 then
    begin
      sql := 'insert into ' + Ftabtyp + ' (camname,adresse) values(:camname,:adresse);';
      dm.tTypen.StartTransaction;
      dm.qTypen.SQL.Text := sql;
      dm.qTypen.Params.ByNameAsString['camname'] := UTF8Decode(CamTypName);
      dm.qTypen.Params.ByNameAsString['adresse'] := UTF8Decode(CamTypAdresse);
    end
    else
    begin
      sql := 'update ' + Ftabtyp +
        ' set camname=:camname, adresse=:adresse where id=:id;';
      dm.tTypen.StartTransaction;
      dm.qTypen.SQL.Text := sql;
      dm.qTypen.Params.ByNameAsString['camname'] := UTF8Decode(CamTypName);
      dm.qTypen.Params.ByNameAsString['adresse'] := UTF8Decode(CamTypAdresse);
      dm.qTypen.Params.ByNameAsInt64['id'] := CamTypID;
    end;
    dm.qTypen.Execute;
    dm.tTypen.Commit;
  except
    on E: Exception do
    begin
      dm.tTypen.RollBack;
      ShowMessage(E.Message);
    end;
  end;
end;

dataspider 13. Apr 2011 14:49

AW: Verwenden von Triggern für Firebird 2.5 DB
 
Hi,

an dieser Stelle bleiben doch einige hängen.
Der Hintergrund:

Deine Datenmenge in deinem DataSet füllst du ja mit Daten.
Dann erfolgt ein Insert und dein Dataset schickt eine Insert - Statement an die DB.
Dein DataSet kennt alle Daten, die du eingegeben hast.
Um auch die Daten zu kennen, die durch Trigger generiert werden, muss das DataSet dazu veranlasst werden,
nach einem Insert quasi eine Syncronisation mit dem Server durchzuführen.

Je nach Komponentenherstelle wir dieses Problem unterschiedlich angegangen.
Die meisten erlauben es, den Generator und das KeyField anzugeben und holen den Wert für die ID selbst.
Deshalb macht es Sinn, im Trigger immer ...if new.id is null then... zu verwenden.

Such mal nach einer Eigenschaft GeneratorName und KeyFieldName.
[EDIT]
Für andere durch Trigger generierte Werte gibt es z.B.
IBO: BufferSyncroFlags oder InvalidateRecord
IBDac: RefreshOptions
...
[/EDIT]



Frank

haentschman 13. Apr 2011 18:55

AW: Verwenden von Triggern für Firebird 2.5 DB
 
Hallo...

2 Dinge gibt es zu beachten:
- wenn du den Trigger für eine automatisch hochzuzählende ID benutzt brauchst du einen Generator dazu. Dieser Generator stellt die ID zur Verfügung die dann in das entsprechende Feld eingetragen wird. Der Name des Generators ist frei wählbar und die Beispiele sind entsprechend anzupassen.
- der Trigger BeforeInsert muß mit dem entsprechenden Code gefüllt sein.

Wenn du einen Datensatz einfügst wird in der Regel die "erzeugte" ID nicht benötigt. Sie ist einfach eingetragen. In Ausnahmefällen braucht man die gerade eingetragene ID um evt. andere Datensätze mit dieser ID zu verknüpfen. Dafür gibt es bei FB returning

:hi:

hoika 15. Apr 2011 07:23

AW: Verwenden von Triggern für Firebird 2.5 DB
 
Hallo,

Zitat:

Was muss ich eigentlich in Delphi tun, damit ein Trigger aus der DB automatisch ausgeführt wird?
Die kurze Antwort ... Nichts.

Du übergibst als ID einfach 0, den Rest macht die DB.
Die Meldung "muss Wert enthalten" kommt von deiner Datenzugriffs-Schicht (also lokal).
Sie hat erkennt, dass das Feld "not null" ist, und will einen Wert haben.
Welcher das ist, ist ihr egal, der Trigger erzeugt ja eh einen anderen.

Die Sache mit dem Generator hast du ja wohl schon gemacht ?
Ohne etwas von deiner DB hier zu sehen, ist das geraten.
Unter IBExpert kannst du per Extract Metadata ja mal deine DB hier zeigen.

Unter IBPhoenix.com findest du auch Beispiele dazu.

Den erzeugten Wert Trigger-wert bekommst du über returning (wie schon weiter oben gesagt).
Ohne das returning müsstest du den Generator selber auslesen (gen_id).
Das ist aber bei FB 2.5 nicht mhr notwendig.


Heiko


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:16 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz