Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Firebird Autoincrement (https://www.delphipraxis.net/191030-firebird-autoincrement.html)

brunoM 1. Dez 2016 08:03

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

Firebird Autoincrement
 
Hallo zusammen
Ich bin daran von AbsoluteDatabase auf Firebird umzusteigen. Firebird ist Neuland und ich habe ein Problem mit Autoincrement-Feldern bzw. mit dem Import von Daten mittels Delphi.

Von AbsoluteDB gewohnt:
tabelle.Insert;
tabelle.Fieldbyname('yx').AsString :='Text....';
tabelle.Fieldbyname('yx').AsString :='Text....';
tabelle.Post.
Soweit so gut - das Autoincrement-Feld wird dabei automatisch erhöt und der Wert mitgespeichert.

Dass es bei Firebird kein Autoincrement-Feld gibt weis ich - habe deshalb auch einen Generator und einen Trigger angelegt bzw. das hat SQL-Manager erledigt. Erfasse ich Daten innerhalb des SQL-Managers funktioniert die Zählung des Autoincrement-Feldes. Versuche ich jedoch über Delphi Daten analog der oben beschriebenen Vorgehensweise zu erfassen, erscheint die Meldung Feld "id" (das besagte Autoincrement-Feld) muss einen Wert haben - scheinbar muss ich da noch etwas unternehmen dass ein Wert vom Generator geliefert und in das id-Feld eingetragen wird. Ich benutze die Unidac-Komponenten von Devart

Leider komme ich nicht weiter - aber vielleicht hat ja hier jemand einen Tipp, jedenfalls schon Danke im Voraus für eure Hilfe.

Gruss
Bruno

haentschman 1. Dez 2016 08:06

AW: Firebird Autoincrement
 
Moin...:P
Prinzipiell geht das auch. :P Zeige mal den Trigger und den Generator.
z.B. Trigger mit Generator (id_gen):
Delphi-Quellcode:
begin
  if (new.id is null) then
    new.id = gen_id(id_gen,1);
end

NicoDE 1. Dez 2016 08:19

AW: Firebird Autoincrement
 
edit: Upz, habe UniDAC überlesen. Ich lasse das folgende für FireDAC trotzdem stehen :)

Interessant für dich sind "UpdateOptions.AutoIncFields" und optional "UpdateOptions.GeneratorName" (wenn der Before-Insert-Trigger sich nicht darum kümmert).
Wenn du mit persistenten Feldern arbeitest, dann sieh dir am Schlüsselfeld die Eigenschaft "AutoGenerateValue" an. Sollte auf "arAutoInc" stehen (mindestens "arDefault"), damit das Dataset sich nach der Aktion den Wert holt (intern mit RETURNING INTO, damit es sich nicht über den Schlüssel ("UpdateOptions.KeyFields" bzw. "ProviderFlags" [...,pfInWhere,pfInKey]), mit einer weiteren Abfrage, die aktuelle Zeile holen muss). Dazu muss am Feld "Required" natürlich auf "False" stehen.

kretabiker 1. Dez 2016 10:41

AW: Firebird Autoincrement
 
Ich habe zwar nicht UNIDAC, aber IBDAC vom gleichen Hersteller, vielleicht gibt es da Ähnlichkeiten.

Es müssen in den Komponenten folgende Felder gesetzt sein (Beispiel für IBCQuery):
- Key Generator (auf den Namen des Generators in FB)
- Key Field (auf das Feld in der Tabelle, welches als "Autoinc" dient)
- evtl. noch den GeneratorMode wechseln von gmPost auf gmInsert

So klappt es bei mir mit Pseudo-Autoinc-Feldern

*** Ups, übersehen, dass du einen Trigger einsetzt. Meine Lösung funktioniert ohne Trigger. Vielleicht hat noch jemand eine Idee bezüglich des Triggers

Neutral General 1. Dez 2016 10:46

AW: Firebird Autoincrement
 
Man muss bei den Komponenten nix einstellen.
Wenn Trigger und Generator korrekt sind reicht es einfach die ID nicht zu setzen und dann wird sie automatisch beim Insert generiert!

Zeig am besten mal den Trigger Code und stell sicher, dass der Trigger als BEFORE INSERT eingestellt und nicht deaktiviert ist.

mrtwo12 1. Dez 2016 11:23

AW: Firebird Autoincrement
 
Moin,

ich meine, wenn mich meine grauen Zellen nicht trügen, es gibt ein Parameter unter Options->RequiredFields in der Table Komponente, die false sein soll.

War, bzw. ist es nicht so, dass der Fehler bei Feld notNull richtig ist wenn man nichts übergiebt, was ja hier richtig ist.

mfg
S.Simon

scrat1979 1. Dez 2016 11:37

AW: Firebird Autoincrement
 
Also ich habe bisher bei den Komponenten noch NIEMALS einen Generator oder Trigger angegeben, sondern lediglich den Trigger in der Datenbank (OnBeforeInsert oder OnBeforePost - weiß ich nicht genau) mit Hilfe eines DB-Managers eingerichtet und gesetzt. Bisher hat alles prima beim Insert über die Komponenten funktioniert... Liegt der Fehler vielleicht doch an einem nicht ausgelösten Trigger?! (Verwende IBDAC und UniDAC von DevArt).

brunoM 1. Dez 2016 11:42

AW: Firebird Autoincrement
 
Zitat:

Zitat von Neutral General (Beitrag 1355104)
Man muss bei den Komponenten nix einstellen.
Wenn Trigger und Generator korrekt sind reicht es einfach die ID nicht zu setzen und dann wird sie automatisch beim Insert generiert!

Zeig am besten mal den Trigger Code und stell sicher, dass der Trigger als BEFORE INSERT eingestellt und nicht deaktiviert ist.

Nachfolgend der Code der durch SQl-Manager generiert worden ist - und der auch intern im SQL-Manager funktioniert:

SET TERM ^ ;

CREATE TRIGGER BI_MDATEN_ID FOR MDATEN
ACTIVE BEFORE
INSERT
POSITION 0
AS
BEGIN
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(MDATEN_ID_GEN, 1);
END^

SET TERM ; ^

brunoM 1. Dez 2016 11:44

AW: Firebird Autoincrement
 
Ich bin noch nicht weiter aber bereits herzlichen Dank für die zahlreichen Antworten!

nahpets 1. Dez 2016 12:11

AW: Firebird Autoincrement
 
Wie ist denn ID in der Datenbank definiert? Als Not Null?
Wenn das von der Datenbank vor dem Ausführen des Triggers geprüft wird, hast Du ohne Angabe einer ID keine Chance.

Ggfls. dashier ändern:
Delphi-Quellcode:
IF (NEW.ID IS NULL) THEN
in
Delphi-Quellcode:
IF (NEW.ID IS NULL) or (NEW.ID = -1) THEN
und dann als ID -1 übergeben.

Bei mir funktionieren Tabellen-, Generator- und Triggerdefinitionen:
SQL-Code:
CREATE TABLE TEXTVERWALTUNG
(
  TEXTVERWALTUNGID Integer,
  ...
);

CREATE GENERATOR GEN_TEXTVERWALTUNGID;

SET TERM ^ ;
CREATE TRIGGER TR_TEXTVERWALTUNGID_BI FOR TEXTVERWALTUNG ACTIVE
BEFORE INSERT POSITION 0
AS BEGIN
  if (NEW.TextverwaltungID is NULL) then NEW.TextverwaltungID = GEN_ID(gen_TextverwaltungID, 1);
END^
SET TERM ; ^

Neutral General 1. Dez 2016 12:13

AW: Firebird Autoincrement
 
Zitat:

Zitat von nahpets (Beitrag 1355125)
Wie ist denn ID in der Datenbank definiert? Als Not Null?
Wenn das von der Datenbank vor dem Ausführen des Triggers geprüft wird, hast Du ohne Angabe einer ID keine Chance.

Wird es aber nicht.

DataCool 1. Dez 2016 12:23

AW: Firebird Autoincrement
 
Hi Bruno,

ich verwende genau die gleiche Konstellation in einem Projekt (Firebird + UniDac).

Ich habe in der Firebird DB auch einen Generator und einen Trigger(Before Insert):

Code:
         if ( (new.id is null) OR (NEW.ID = 0) ) then
             new.ID = GEN_ID(GEN_IDPOOL,1);
Jetzt gibt es 2 Varianten die funktionieren sollten:

1. Im Objekt-Inspektor, beim dem PK Field die Property "Required" auf false setzen

2. Im Delphi-Code im Event im Event "OnBeforePost" das Feld selber befüllen über den Generator:
Delphi-Quellcode:
procedure TfrmKonzepte.tbl_DataBeforePost(DataSet: TDataSet);
var iID : Int64;
begin
  inherited;
  // Neuer Datensatz ?
  if DataSet.State = dsInsert then begin
    // neue ID selber ermitteln und setzen dazu Stored procedure verwenden,
    // die den internen Generator benutzt
    iID := dmGlobalDB.GetGeneratorValueFromSP(dmGlobalDB.DBCon, cSPGetPrimaryKey, 0);
    if iID > 0 then // erfolgreich die neue PK-ID ermittelt diese dann setzen
      tbl_DataID.AsLargeInt := iID;
  end;
end;

function TdmGlobalDB.GetGeneratorValueFromSP(AConnection: TUniConnection;
                                             const AStoredProcedureName: string;
                                             iDefault: Int64): Int64;
var Qry : TUniQuery;
begin
  Result := iDefault;
  Qry := TUniQuery.Create(nil);
  try
    Qry.Connection := AConnection;
    Qry.SQL.Text := 'SELECT * FROM '+AStoredProcedureName;
    Qry.Active := True;
    if not Qry.Eof then begin
      if not Qry.Fields[0].IsNull then
        Result := Qry.Fields[0].AsLargeInt;
    end;
    Qry.Active := False;
  finally
    FreeAndNil(Qry);
  end;
end;
Ich selber verwende Variante 2.

Gretes Data

user0815 1. Dez 2016 12:37

AW: Firebird Autoincrement
 
per Quellcode anlegen

Delphi-Quellcode:
// table
      q.SQL.Add('CREATE TABLE MyTableName (');
      q.SQL.Add(' ID INTEGER NOT NULL,');
      q.SQL.Add(' MyText VARCHAR(75) COLLATE UNICODE,');
      q.SQL.Add(' MyValue FLOAT DEFAULT 0,');
      q.SQL.Add('CONSTRAINT PK_MyTableName PRIMARY KEY (ID))');
      q.ExecSQL;
// Generator
      q.SQL.Clear;
      q.SQL.Add('CREATE GENERATOR MyTableName_GEN');
      q.ExecSQL;

      q.SQL.Clear;
      q.SQL.Add('SET GENERATOR MyTableName_GEN TO 0');
      q.ExecSQL;
// Trigger
      q.SQL.Clear;
      q.SQL.Add('CREATE TRIGGER ID FOR MyTableName ACTIVE BEFORE INSERT POSITION 0 AS');
      q.SQL.Add('begin');
      q.SQL.Add(' if ( (new.ID is null) or (new.ID = 0) )');
      q.SQL.Add(' then new.ID = gen_id(MyTableName_GEN, 1);');
      q.SQL.Add('end');
      q.ExecSQL;

MyRealName 1. Dez 2016 13:41

AW: Firebird Autoincrement
 
Bei unidac reicht es nicht, das als autoinc field anzugeben und den trigger zu haben, man muss aus DMLRefresh auf True setzen, damit er die Werte entsprechend im Dataset updated (von der DB)

mikhal 1. Dez 2016 14:08

AW: Firebird Autoincrement
 
Ich nutze die persistenten Felder, hier wird beim PK-Feld die Property Required auf False gesetzt, in den Optionen der TUniQuery wird auf dem Reiter Optionen einfach der Name des Generators in der Eigenschaft KeyGenerator eingetragen - das wars.

Grüße
Mikhal

brunoM 1. Dez 2016 14:54

AW: Firebird Autoincrement
 
Herzlichen Dank an alle - das Problem hat sich gelöst!!

Es liegt tatsächlich an "Requirdedfields" in den Optionen der UniTable-Komponente.
Ich habe dieses auf False gesetzt.
Weiter habe ich in der Rubrik "Specificoptions" folgende Werte geändert:

GeneratorMode := gmInsert
KeyGenerartor := Name des Generators

Ob das einen Eifluss hat oder ob es nur an "Requiredfields" liegt habe ich noch nicht ausporbiert. Jedenfalls funktioniert es super.

Nochmals herzlichen Dank für die Tipps.

Gruss
Bruno


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:53 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