Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Autowerte bei Firebird setzen (https://www.delphipraxis.net/47383-autowerte-bei-firebird-setzen.html)

FBrust 10. Jun 2005 11:39

Datenbank: Firebird • Version: 1.5 • Zugriff über: Zeos 6.5.1

Autowerte bei Firebird setzen
 
Hallo,

ich bastel gerade an einem Programm, dass über die Zeos-Komponenten auf einen Firebird-Server zugreift.

Nun habe eine Tabelle in meiner FB-Datenbank, die über ein Feld "ID" verfügt. Dieses Feld ist primärer Index und als "autoinc" definiert.

Wenn ich nun einen Datensatz speichern will (über den Navigator), erhalte ich die Fehlermeldung, dass der Insert-Befehl gescheitert wäre.

Wenn ich dann über ein DBEdit-Feld einen Wert für ID eintrage, klappt der Insert. Dabei sollte doch ein Autowert automatisch gesetzt werden, oder?

Für das Feld ID hat IBExpert noch einen Generator angelegt, der wohl für diese AutoInc-Sachen zuständig ist. Muss ich den irgendwie anstoßen/ausführen? Wenn ja, wie?


Gruß
Frank

MagicAndre1981 10. Jun 2005 11:54

Re: Autowerte bei Firebird setzen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von FBrust
Hallo,

ich bastel gerade an einem Programm, dass über die Zeos-Komponenten auf einen Firebird-Server zugreift.

Nun habe eine Tabelle in meiner FB-Datenbank, die über ein Feld "ID" verfügt. Dieses Feld ist primärer Index und als "autoinc" definiert.

Wenn ich nun einen Datensatz speichern will (über den Navigator), erhalte ich die Fehlermeldung, dass der Insert-Befehl gescheitert wäre.

Wenn ich dann über ein DBEdit-Feld einen Wert für ID eintrage, klappt der Insert. Dabei sollte doch ein Autowert automatisch gesetzt werden, oder?

Für das Feld ID hat IBExpert noch einen Generator angelegt, der wohl für diese AutoInc-Sachen zuständig ist. Muss ich den irgendwie anstoßen/ausführen? Wenn ja, wie?


Gruß
Frank

Hi, die Zeos-Kompos sind mir leider nicht vertraut, aber bei den IBX-Kompos musst du über das Property "GeneratorField" angeben welches Feld das autoinc-Feld ist und wo der Wert erhöht wird (siehe Anhang).

Schau mal nach, ob es bei den Zeos auch so was gibt.

André

FBrust 10. Jun 2005 12:12

Re: Autowerte bei Firebird setzen
 
Hallo André,

hab nachgesehen, es gibt für das einzelne Feld über den Feldeditor der ZTable-Komponente die Eigenschaft "AutoGenerateValue", aber wenn ich die auf "arAutoInc" setze, erhalte ich trotzdem die gleiche Fehlermeldung.


Gruß
Frank

Grendel 10. Jun 2005 12:20

Re: Autowerte bei Firebird setzen
 
Als ich das letzte mal mit Firebird gearbeitet habe (war gerade die 1.0 frisch raus) gabe es sowas wie ein "autoinc" Flag garnicht. Stattdessen musste man sich ein Konstrukt aus einem Trigger und einer Sequenz basteln wobei die Sequenz die ID hochzählt und der Trigger diese einfügt.

Daher meine Frage: Wie hast Du das Feld als autoincrement definiert?

Falls die 1.5 Firebird o.g. Konstrukt nicht mehr benötigt vergiss alles was ich gesagt habe :)

Bis neulich ...

FBrust 10. Jun 2005 15:56

Re: Autowerte bei Firebird setzen
 
Hallo Grendel,

ich hab die Datenbank und die Tabellen mit IBExpert erzeugt. Dort kann man in dem Dialog zur Tabellengenerierung "autoinc" ankreuzen. Aufgrund dieser Angabe erzeugt IBExpert dann einen sog. Generator mit einem definierten Startwert.

Allerdings weiss ich nicht, ob ich den Generator extra ansprechen muss, da ja z. B. beim ADS oder bei der BDE Autoinc-Felder automatisch hochgezählt werden, hier passiert allerdings nix.

Natürlich kann ich mir mit "SELECT MAX..." den höchsten Wert aus der Tabelle holen und um 1 erhöhen, aber dann bräuchte ich kein Autoinc....


Gruß
Frank

Albi 10. Jun 2005 16:11

Re: Autowerte bei Firebird setzen
 
Hallo,

dann erzeuge doch einfach noch den passenden Trigger dazu und du brauchst dich um die Erstellung nicht mehr zu kümmern, da die DB das für dich erledigt.

SQL-Code:
AS
BEGIN
  IF (NEW.ID IS NULL) THEN
      NEW.ID = GEN_ID(DB_Name_ID_GEN, 1);
END

FBrust 10. Jun 2005 16:16

Re: Autowerte bei Firebird setzen
 
Hallo Albi,

ist ja schön und gut, aber wozu brauche ich dann die "AutoInc"-Definition? Und wie nutze ich die?


Gruß
Frank

marabu 10. Jun 2005 16:23

Re: Autowerte bei Firebird setzen
 
Hallo Frank,

eine Möglichkeit zur "automatischen" Vergabe von ID für deine Tabelle TBL unter Verwendung eines Generators ist ein Trigger, wie er im Handbuch steht. Ich gehe davon aus, dass der Generator so heißt wie die Tabelle.

SQL-Code:
CREATE TRIGGER "TBL_BI0" FOR "TBL"
ACTIVE BEFORE INSERT POSITION 0
as
begin
  if (new.id = 0) then
    new.id = gen_id(TBL, 1);
end
Ich habe immer einen solchen Trigger - und benutze ihn dann nicht. Der Trigger dient bei mir nur der Unterstützung von bulk-load Operationen. Den ID für single record inserts hole ich mir vom Generator und setze ihn in der Anwendung. Auf diese Weise habe ich die ID für meinen Programm-Kontext. Echte AutoInc-Felder machen bei primary key Feldern mehr Probleme als Freude.

Grüße vom marabu

Albi 10. Jun 2005 16:32

Re: Autowerte bei Firebird setzen
 
Hallo,

Du sagst damit nichts weiter wie das ein Generator erzeugt wird. Diesen kannst Du entweder selber in der StoredProcedure machen über


SQL-Code:
...
...
Insert Into DB (ID,...,...)
Values (gen_ID(DB,1),...,...)
Oder Du erzeugst noch den passenden Trigger, dann kannst Du dir in der SP eben das Feld ID sparen. Und die DB kümmert sich um die Vergabe der DB.

Welche Vorteile oder Nachteil das hat, kann ich dir auch nicht sagen. Aber ich bevorzuge immer die Variante mit den Trigger (wahrscheinlich aus Bequemlichkeit :-D )

FBrust 10. Jun 2005 17:05

Re: Autowerte bei Firebird setzen
 
Hallo,

ich habe mittlerweile einen möglichen Grund gefunden.

Wenn man im IBExpert eine Tabelle anlegt, kann man auch ein Feld als AutoInc definieren. IBExpert erzeugt dann einen Generator und verknüpft ihn dann mit dem Feld. Allerdings scheint IBExpert die Verbindung nicht in der Datenbank zu speichern, da beim Bearbeiten der Tabelle die entsprechende Checkbox leer ist.

Weist man nun erneut den bereits definierten Generator zu und speichert ab, so ist bei erneutem Öffnen der Feldeigenschaften die Checkbox wieder leer (nicht gesetzt).

Also werd ich wohl einen Trigger einbauen, der beim Insert das Feld ID um eins erhöht.


Danke für Eure Antworten.


Gruß

Frank

Albi 10. Jun 2005 18:27

Re: Autowerte bei Firebird setzen
 
Hallo,

dann schaue Dir mal die Feldbeschreibung an. Da wirst Du sehen, dass der Primary Key gesetzt wurde, sich die Datenbank also die Einstellung gemerkt hat. Wenn Du beim anlegen der DB halt AutoInc auswählst, ist das wohl das gleiche wie der Primary Key. Also ein eindeutiger Schlüssel, der nur einmal vorkommt.

Ob Du nun diesen Schlüssel selber erstellst oder über einen Trigger dies machen lässt, bleibt im Grunde dir überlassen.

Ich habe habe das Feld AutoInc im IBExpert nur gesehen, wenn du die Table bzw. das Feld anlegst, danach ist es wie schon gesagt nur über die Feldeigenschaften zu erkennen, in welchem Verhältnis was zu wem steht. Hast Du das Feld vielleicht mit dem "Not Null" verwechselt?

Robert_G 10. Jun 2005 18:41

Re: Autowerte bei Firebird setzen
 
Zitat:

Zitat von marabu
Ich habe immer einen solchen Trigger - und benutze ihn dann nicht. Der Trigger dient bei mir nur der Unterstützung von bulk-load Operationen. Den ID für single record inserts hole ich mir vom Generator und setze ihn in der Anwendung. Auf diese Weise habe ich die ID für meinen Programm-Kontext. Echte AutoInc-Felder machen bei primary key Feldern mehr Probleme als Freude.

Interssant ist die Geschichte von Interbase. eines der ersten "Features", die Borland in IB nach der Übernahme "eingebaut" hatte, war das Entfernen von rüggabewerten aus DML Statements... :?
Seitdem muss man tatsächlich so vorgehen, wie du es beschrieben hast. In Ora mache ich es meist so:

Delphi-Quellcode:
create or replace trigger X_PkTrig
 before INSERT or UPDATE ON SomeSchema.X
 -- rename New and Old, they could be used as table or column names ...
  REFERENCING New AS New$Rec Old AS Old$Rec
  for each row
begin
  if Inserting then
    -- get next value from sequence
    SELECT SomeSchema.X_PkSeq.NextVal
    INTO  :New$Rec.ID
    FROM  dual;
  elsIf Updating then
    -- prevent changes of ID
    :New$Rec.ID := :Old$Rec.ID;
  end if;
end SomeSchema.X_PkTrig;
Die ID bekomme ich so:
SQL-Code:
insert into X (a,b) values (:a,:b) returning id into :id;
Wenn man die Cache size der sequence passend wählt macht es sich auch in großen bulk inserts nicht wirklich bemerkbar. ;)
Das schöne an der Methode ist, dass ich sie komplett automatisch ablaufen lassen kann. (Also die Erzeugung von Trigger/Sequence) :)

btw: Seit wann kann FB Bulk DML? :gruebel:

FBrust 11. Jun 2005 00:20

Re: Autowerte bei Firebird setzen
 
Hallo Albi,

Zitat:

Ich habe habe das Feld AutoInc im IBExpert nur gesehen, wenn du die Table bzw. das Feld anlegst, danach ist es wie schon gesagt nur über die Feldeigenschaften zu erkennen, in welchem Verhältnis was zu wem steht. Hast Du das Feld vielleicht mit dem "Not Null" verwechselt?
Nein, ich hab "not null" zusätzlich ausgewählt, es gibt ja beides bei der Felderstellung. Ich war es halt vom ADS und von der BDE so gewohnt, dass man ein Feld als "Autoinc" definiert und ab dann kümmert sich die Datenbank um das Hochzählen, ob das Feld Primary key war oder nicht.

Nun, wie gesagt, ich bau dann eben einen Trigger ein.


Gruß
Frank

mschaefer 11. Jun 2005 21:27

Re: Autowerte bei Firebird setzen
 
Moin, Spätmoin

Zitat:

Den ID für single record inserts hole ich mir vom Generator und setze ihn in der Anwendung
Das ist eigentlich das leidige an Zeos, das es sich hier nich tselbst drum kümmert. Wenn man die ID nicht selbst holt und in das Primärindexfeld schreibt verliert der Dataset den aktuellen Record nach einem Post. Das gibt in einem Grid dann seltsame Sprünge. Bisher habe ich das so gelöst, das ich im Before-Iinsert-Ereignis mir eine Query auf den Generator gesetzt habe und den neuen Generatorwert dann vor einem Post eintrage. Wenn ein Zeos-Entwickler hier mitliest, dann überdenkt hier doch mal eine automatisierung.

Grüße // Martin

Robert_G 11. Jun 2005 22:07

Re: Autowerte bei Firebird setzen
 
Zitat:

Zitat von mschaefer
Moin, Spätmoin

Zitat:

Den ID für single record inserts hole ich mir vom Generator und setze ihn in der Anwendung
Das ist eigentlich das leidige an Zeos, das es sich hier nich tselbst drum kümmert. Wenn man die ID nicht selbst holt und in das Primärindexfeld schreibt verliert der Dataset den aktuellen Record nach einem Post. Das gibt in einem Grid dann seltsame Sprünge. Bisher habe ich das so gelöst, das ich im Before-Iinsert-Ereignis mir eine Query auf den Generator gesetzt habe und den neuen Generatorwert dann vor einem Post eintrage. Wenn ein Zeos-Entwickler hier mitliest, dann überdenkt hier doch mal eine automatisierung.

Grüße // Martin

Warum leitest du nicht einfach von dem DataSet ab.
Verpasse ihm eine Eigenschaft mit dem Generatornamen, überschreibe OnBeforePost und gut ist. ;)

mschaefer 12. Jun 2005 00:38

Re: Autowerte bei Firebird setzen
 
Tach Robert,

ja - genausowas habe ich dann auch gemacht (muß ja nicht gleich mit der Tür ins Haus fallen), aber leider muß ich jetzt immernoch bei jedem Dataset den SQL-Befehl für das holen des Trickers extra eintragen. Im Moment habe ich eine zusätzliche StringListe mit der Generator-Abfrage die im BeforePost über ein temporäres Dataset abläuft...

Mir ist es also nich gelungen, daß so zu verallgemeinern, daß man einfach eine Eigenschaft GetGeneratorrBeforePost auf True setzt und gut. Das ist leider nervig.

Grüße // Martin

Robert_G 12. Jun 2005 23:26

Re: Autowerte bei Firebird setzen
 
Ich hoffte, dass vielleicht noch ein paar mehr Infos kommen würden...

Ehrlich gesagt hoffe ich, dass ich das falsch verstanden habe. ;)
Zitat:

Zitat von mschaefer
ja - genausowas habe ich dann auch gemacht (muß ja nicht gleich mit der Tür ins Haus fallen), aber leider muß ich jetzt immernoch bei jedem Dataset den SQL-Befehl für das holen des Trickers extra eintragen. Im Moment habe ich eine zusätzliche StringListe mit der Generator-Abfrage die im BeforePost über ein temporäres Dataset abläuft...

Genau hierum gates.
Zitat:

Zitat von mschaefer
Mir ist es also nich gelungen, daß so zu verallgemeinern, daß man einfach eine Eigenschaft GetGeneratorrBeforePost auf True setzt und gut. Das ist leider nervig.

Nur um ein paar Ansätze in den Raum zu werfen.
  • Eine *piep*-normale string Property, die den Namen des Generators enthält.
    Im OnBeforeXXX wird sich dann der neue Wert aus diesem Generator geholt, falls ein Name eingetragen wurde.
  • Wieder diese Property, doch nun mit einem Property Editor, der alle Generatoren auflistet, die in Triggern verwendet werden, die den PK der Tabelle aus dem SELECT Statement verwenden.
    FB sollte hierfür System views anbieten, die Abhängigkeiten abbilden.
    Gibt es Extra Statements für DML? Wenn ja, dann natürlich für's INSERT Statement. (Sorry, ich habe Zeos ewig nicht angerührt...)
  • Das könnte man soweit treiben, dass beim Ändern des SQL Strings automatisch der Generator geholt wird, wenn nur einer ins Suchmuster passt (was wohl in 99% aller Fälle auch der Fall sein wird ;) )
    Der letzte Teil sollte vielleicht über eine bool'sche Property laufen, da man sicher nicht ständig nach Generatoren suchen lassen will. Wobei man hier natürlich auch gegen SQL.UpdateCount prüfen sollte. ;)
Das Ganze sollte IMHO im erträglichen Rahmen bleiben. (Also vom reinen Code Umgfang...)

Hansa 13. Jun 2005 00:29

Re: Autowerte bei Firebird setzen
 
Zitat:

Zitat von Robert_G
...Wieder diese Property, doch nun mit einem Property Editor, der alle Generatoren auflistet, die in Triggern verwendet werden, die den PK der Tabelle aus dem SELECT Statement verwenden. FB sollte hierfür System views anbieten, die Abhängigkeiten abbilden...

...und womit keiner richtig was anfangen kann. 8) Was soll denn der Firlefanz da ? Ich fange doch nicht an, mir die einzelnen Trigger selber zusammenzusuchen. :zwinker: Für die Vergabe von IDs ist nur der Trigger zuständig, sonst keiner ! Eventuell ist ein falsch gesetztes Commit verantwortlich, wenn es nicht läuft, wie gewünscht. Ich bin jetzt auch einer, der zu unterscheiden weiß, ob irgendwas besser direkt in der DB genacht werden sollte oder im Programm. Die Vergabe der ID gehört in diesem Zusammenhang aber eindeutig in die DB.

Robert_G 13. Jun 2005 00:50

Re: Autowerte bei Firebird setzen
 
Zitat:

Zitat von Hansa
...und womit keiner richtig was anfangen kann. 8) Was soll denn der Firlefanz da ? Ich fange doch nicht an, mir die einzelnen Trigger selber zusammenzusuchen. :zwinker:

Verdammt nochmal... Lerne Lesen, Hansa! Lesen, Nachdenken und VERSTEHEN! :evil:
Nur weil DU es nicht kapierst musst du nicht alle anderen als Vollidioten abstempeln. :roll:
Zitat:

Zitat von Hansa
Für die Vergabe von IDs ist nur der Trigger zuständig, sonst keiner !

Da sind wir ausnahmsweise mal einer Meinung. Dummerweise sieht es FB anders. Siehe mein INSERT Statement weiter oben. Um es durch den Trigger abhandeln zu können bräuchte man Rückgabewerte aus DML, die FB nicht kennt.
Zitat:

Zitat von Hansa
Ich bin jetzt auch einer, der zu unterscheiden weiß, ob irgendwas besser direkt in der DB genacht werden sollte oder im Programm. Die Vergabe der ID gehört in diesem Zusammenhang aber eindeutig in die DB.

Da sind wir wohl eindeutig getrennter Meinung, wobei der letzte Satz auf ein DBMS <> IB/FB zutrifft.

Wie man eindeutig zwischen den Zeilen herauslesen kann, steht mir deine arrogante Art, anderen deine Unwissenheit bekannt zu tun, mal wieder bis Oberkante Unterlippe. Wenn du in dem Thread weiter rumpupst vergeht mir ziemlich schnell die Lust daran.

Ich glaube aber, dass das schade wäre. Denn man könnte hier sicherlich einige stupide Codezeilen und Nerven einsparen. ;)

Hansa 13. Jun 2005 01:34

Re: Autowerte bei Firebird setzen
 
Zitat:

Zitat von Robert_G
...Wie man eindeutig zwischen den Zeilen herauslesen kann, steht mir deine arrogante Art, anderen deine Unwissenheit bekannt zu tun,...

Der Titel des Oberschlaumeiers gehört eindeutig dir. :thumb: :mrgreen: Leider reicht es nun aber nicht aus, mit ein paar Wörtern um sich zu schmeißen, die Leute zu verwirren und im Grunde genommen nichts zu sagen. Sorry, aber das ist einfach zuwenig.

alcaeus 13. Jun 2005 01:40

Re: Autowerte bei Firebird setzen
 
Hallo ihr,

ich will euch mal bitten, sachlich zu bleiben. So eine "Diskussion" bringt wirklich keinem was. Auch wenn ich die Materie nicht wirklich verstehe (:oops: ich bin eben kein Datenbankmensch), aber ich denke der Vorschlag von Robert hat durchaus was sinnvolles, was nicht durch irgendwelche Kommentare "dummgeredet" werden muss.

@Hansa: tut mir Leid wenn ich dich direkt anspreche, aber du bist nicht der, der versucht hat das Problem zu loesen. Ich bitte dich also, die unnuetzen Kommentare fuer dich zu behalten, oder diesen Disput mit Robert per PN auszutragen. Das was hier abgeht hilft dem Threadersteller beim besten Willen nicht, und auch wenn es fuer den einen nur "Woerter, die verwirren" sind, fuer den anderen kann so ein Loesungsweg durchaus Sinn ergeben. Und um auf den Kommentar des "Oberschlaumeiers" einzugehn: nur weil jemand versucht zu helfen, und dabei auch ziemlich komplizierte Loesungsvorschlaege kommen, muss man jemanden nicht beleidigen, nur weil man diese nicht versteht, sich nie damit befasst hat oder weil sie einen ganz einfach nicht interessieren. Das ist meine Meinung.

Und nun, back to topic please. Falls jemand von euch noch etwas dazu zu sagen hat, kann er dies gerne per PN tun, aber weitere offtopic-Postings werde ich nicht dulden.

Greetz
alcaeus

Marcel Gascoyne 13. Jun 2005 07:25

Re: Autowerte bei Firebird setzen
 
Von automatisch generieren PK's halte ich auch nicht sehr viel. Eine einfache Möglichkeit ist die Verwendung einer GUID als PK, die kann man ganz einfach mit Delphi und auch aus anderen Anwendungen erzeugen:

Delphi-Quellcode:
var
  MyGuid: TGUID;
  MyPK: string;
begin
  CreateGUID(MyGuid);
  MyPK := StringReplace(Copy(GuidToString(MyGuid),2,36),'-','',[rfReplaceAll]);
end;
Der PK ist dann vom Typ varchar(32) in der Firebird Datenbank.

Gruß,
Marcel

mschaefer 13. Jun 2005 07:55

Re: Autowerte bei Firebird setzen
 
Moin zusammen,

das Thema wird gerade richtig interessant!

Marcel hat gerade Hansa´s Ansatz es vom Programm aus zu steuern mit einem praktischen Beispiel belegt. Für eine SingleUser-Anwendung ist das vom Aufwand her der ergonomischste Weg. Im kleinen Netz kann ich auch die IP´s zur Guid einbeziehen und dann ist es auch hier Rechnereindeutig.


Wie das aber im Internet mit dynamischer Adressvergabe dann laufen soll ist mir allerdings nicht ganz klar. Also wie kann ich die Eindeutigkei in einem Mehrbenutzersystem wirklich garantieren. Selbst neige ich daher zu Roberts-Ansatz (ja wir sind tatsächlich mal einer Meinung!):
Zitat:

Eine *piep*-normale string Property, die den Namen des Generators enthält.
Im OnBeforeXXX wird sich dann der neue Wert aus diesem Generator geholt, falls ein Name eingetragen wurde.
Wir verfolgen den Primärschlüssel über den getriggerten Generator zu vergeben und das Dataset-Object (TZQuery) die Fähigkeit anzugedeihen sich vor einem Insert den aktuellen Generator-Wert zu holen um sprünge in der Griddarstellung zu vermeiden. Die Datenbankvariante hat zuden den Vorteil, das auch bei Store-Procedures für den PID-Wert ein AutoInc ausgeführt wird.


So jetzt komme ich zu meinem aktuellen Problem dazu: Mir ist es n i c h t gelungen nur mit dem Generatornamen als String den aktuellen Generatorwert abzufragen o h n e eine Stored-Procedure zu bemühen. Kennt hier jemand ein eLösung ???

Grüße // Martin

Stevie 13. Jun 2005 08:41

Re: Autowerte bei Firebird setzen
 
Hallo zusammen,

sehr interessant, was hier diskutiert wird.
Darüber hab ich mir schon des öfteren mal Gedanken gemacht.

Aber, was ihr in diesem Kontext leider vergessen habt ist folgendes:
Die Zeos sind nicht nur für Firebird / Interbase !!!

In MySQL gibts z.B. keine Generatoren, in Oracle sind es Sequenzen usw ...

Das heißt, es muss ein gemeinsamer Nenner gefunden werden, um das Problem der servergenerierten Felder zu behandeln.
(worüber ich mich auch schon derbe bei den Zeos-Kompos aufgeregt hab! *g*)

Was es zudem in Zeos (noch) nicht gibt, ist die Möglichkeit, einen einzelnen Datensatz zu refreshen,
was auch in diesen Bereich fällt. Also hab ich mir folgendes überlegt:

- die TSQLUpdate-Kompo muss um einen 4. SQL erweitert werden: RefreshSQL
- es muss die Möglichkeit geben, Generator/Sequence/was-auch-immer-Felder
nach einem Insert zurückzubekommen --> evtl eigene Komponente?

Würd mich freuen, wenn ihr dazu mal eure Meinung äußern würdet. ;-)

MfG
Stevie

P.S.: Den Weg, ein ID-Feld in der DB zu füllen, halte ich für den saubersten,
auch wenn es im Moment etwas schwierig ist. (zumindest mit Zeos)

marabu 13. Jun 2005 09:01

Re: Autowerte bei Firebird setzen
 
Hallo Martin,

Zitat:

Zitat von mschaefer
Mir ist es n i c h t gelungen nur mit dem Generatornamen als String den aktuellen Generatorwert abzufragen o h n e eine Stored-Procedure zu bemühen. Kennt hier jemand eine Lösung ???

meinst du das hier:

SQL-Code:
SELECT GEN_ID(DeinGeneratorName, 0) FROM RDB$DATABASE
Grüße vom marabu

Nachtrag:

Relational gespeichert wird in der Datenbank nur ein Zugriffsschlüssel für den Generator. Damit wird die Forderung erfüllt, dass der Generator außerhalb der Transaktionsverwaltung geführt werden muss. Die Werte können also nicht als Spaltenwerte einer Systemtabelle abgefragt werden.

mschaefer 13. Jun 2005 09:18

Re: Autowerte bei Firebird setzen
 
Moin, Jihu!

Marabu, genau der Schritt hat mir gefehlt. Klasse !

Jetzt holen wir Stevie ins Boot und bauen Roberts 'abgedrehtes' Zeug in eine abgeleitete TZQuery-Komponente ein
und am Ende fällt dann auch für Hansa was praktisches an. Denn eine solche Query verliert nicht nach einem Post
ihren aktuellen Datensatz sondern bleibt auf ihm stehen.

Mit etwas zeitlicher Verzögerung, da noch aktuelle Aufgaben anstehen, kommt nachher mein Komponentenprototyp!

Grüße // Martin

Stevie 13. Jun 2005 09:22

Re: Autowerte bei Firebird setzen
 
Zitat:

Zitat von mschaefer
Jetzt holen wir Stevie ins Boot ...

Wenn, dann hol ich euch ins (Zeos-)Boot! :mrgreen:

Aber Scherz beiseite, bin mal gespannt, was da nachher kommt. :wink:

P.S. Für MySQL und SQLite funktioniert das mit dem AutoInc-Werte holen.
Bei MySQL wird das folgendermaßen gemacht (ZDbcMySqlResultSet.pas):
Delphi-Quellcode:
{**
  Posts updates to database.
  @param Sender a cached result set object.
  @param UpdateType a type of updates.
  @param OldRowAccessor an accessor object to old column values.
  @param NewRowAccessor an accessor object to new column values.
}
procedure TZMySQLCachedResolver.PostUpdates(Sender: IZCachedResultSet;
  UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor);
var
  Statement: IZStatement;
  ResultSet: IZResultSet;
begin
  inherited PostUpdates(Sender, UpdateType, OldRowAccessor, NewRowAccessor);

  if (UpdateType = utInserted) and (FAutoColumnIndex > 0)
    and OldRowAccessor.IsNull(FAutoColumnIndex) then
  begin
    Statement := Connection.CreateStatement;
    ResultSet := Statement.ExecuteQuery('SELECT LAST_INSERT_ID()');
    try
      if ResultSet.Next then
        NewRowAccessor.SetLong(FAutoColumnIndex, ResultSet.GetLong(1));
    finally
      ResultSet.Close;
      Statement.Close;
    end;
  end;
end;
Ich denke, an dieser Stelle sollte man bei den anderen Protokollen auch ansetzen.
Und da dann mit der angesprochenen Eigenschaft Sequenz/Generator-Name.

mschaefer 13. Jun 2005 10:54

Re: Autowerte bei Firebird setzen
 
Moin,

also das jetzt gleich in Zeos einzuordnen dürfte aufgrund meines etwas veralteten Standes so wohl nich sinnig sein. Aber so kommt zunächst meine angeflanschte Minikomponente:

Delphi-Quellcode:
unit UNIT_TzEnhDataset;
{                                                                              }
{                                                                              }
interface uses
 ZIbSqlQuery, dialogs, Classes,  SysUtils, DB,      DBCommon;
type
{                                                                              }
{                                                                              }
  TzEnhDataset   = class( TZCustomIbSqlDataset )
  private       {                                                             }
                  FGeneratorName               : String;
                  function Get_New_PID        : string;
  public        {                                                             }
                  constructor Create
                  (           AOwner                : TComponent);    override;
                  destructor Destroy;                                 override;
                  procedure  DoBeforeInsert;                          override;
  published     {                                                             }
                 property   GeneratorName         : String
                                                      read FGeneratorName
                                                      write FGeneratorName;
  end;
{                                                                              }

  TEnh_TZQuery  = class(TzEnhDataset)
  public        {                                                             }
                   property MacroCount;
                   property ParamCount;

  published     {                                                             }
                   property MacroChar;
                   property Macros;
                   property Params;
                   property ParamCheck;
                   property DataSource;
                   property Sql;
                   property RequestLive;
                   property Active;
   end;

{                                                                              }
   implementation
{                                                                              }
{  TzEnhDataset                                                               }



  {    }       constructor  TzEnhDataset.Create(AOwner: TComponent);
               begin
                        inherited Create(AOwner);
               end;

  {    }       destructor   TzEnhDataset.Destroy;
               begin
                        inherited Destroy;
               end;

  {    }       function  TzEnhDataset.Get_New_PID : string;
               var
                    PIQ  : TEnh_TZQuery;
               begin
                    Result := '0';
                    if (  OV_PID_Insert   )
                    and (  OV_PID_Insert_SQL.Text <> '' )
                    and (  Database <> nil         ) then
                    begin
                           PIQ         := TCR_Query.Create(nil);
                           PIQ.Database := Database;
                           PIQ.sql.text := 'SELECT GEN_ID(' + FGeneratorName + ', 0) FROM RDB$DATABASE';
                           PIQ.active  := true;
                           Result      := PIQ.FieldList.Fields[0].AsString;
                           PIQ.Active  := false;
                           PIQ.destroy;
                    end;
               end;


  {    }       procedure  TzEnhDataset.DoBeforeInsert;
               begin
                   Edit;
                   {Zu Testzwecken wird davon ausgegangen das PID das erst Feld ist}
                   FieldList.fields[0].AsString := Get_New_PID;
                   inherited DoBeforeInsert;
               end;

{                                                                                }
end.
Mit Unterstützung ist soetwas sicherlich in Zeos einzuordnen und sicherlich aus dem Rohzustand zu bekommen.
Muß mir heute Mittag mal das CVS mal installieren. Soweit stelle ich das zunächst mal zur Diskussion

Einen Haken hat das allerdings noch. Das Lesen des Generators erhöht ihn leider nicht, sondern erst der Post.
Das hat einige Milisekunden Unsicherheit. Vielleicht hat Marabu da noch eine Idee.

Grüße // Martin

marabu 13. Jun 2005 11:07

Re: Autowerte bei Firebird setzen
 
Hallo Martin,

Zitat:

Zitat von mschaefer
Das Lesen des Generators erhöht ihn leider nicht, sondern erst der Post.

du hattest nach dem aktuellen Wert eines Generators gefragt. Die Übergabe von 0 an den zweiten Parameter von GEN_ID() stellt sicher, dass der Wert nur ausgelesen und nicht verändert wird. Was du brauchst ist eher der Standard-Aufruf GEN_ID(GeneratorName, 1) - wobei die 1 eine Standardannahme sein sollte.

marabu

Stevie 13. Jun 2005 11:17

Re: Autowerte bei Firebird setzen
 
Generell würde ich es bevorzugen, den Wert nach dem Posten zu erfragen und ihn dann in das RecordSet zu holen, so wie es oben bei MySQL im Moment schon der Fall ist. Dies würde dem insert into ... returning ... into ... von Oracle entsprechen, welches imho die sauberste Lösung ist. Und all das muss in den entsprechenden dbc-units eingebaut werden.

Ich sag's hier mal in aller Deutlichkeit:
Ich halte nichts davon, automatisch generierte Werte zum Client zu holen,
um diese wieder in die DB zu schreiben, wenn diese das selber kann!

mschaefer 13. Jun 2005 11:20

Re: Autowerte bei Firebird setzen
 
Moin, ja das gibt doch ein Bild

Delphi-Quellcode:
         PIQ.sql.text := 'SELECT GEN_ID(' + FGeneratorName + ', 1) FROM RDB$DATABASE';
Und da keimt doch so etwas wie Optimismus auf! Zeos geht mal nicht eben, werde mir das aber heute abend mal genauer anschauen.
Selbst spare ich dadurch schon eine StoredProcedure und einges an Zusatzquellcode.

/Edit: Das auf AfterInsert umzustellen ist letzlich nur eine Namensumbenennung. Das analog zu den anderen Zeosroutinen zu implementieren macht natürlich sinn. Dazu muß man die aber etwas besser kennen, als das mein aktueller Stand ist. /Edit

Grüße // Martin

Robert_G 13. Jun 2005 12:01

Re: Autowerte bei Firebird setzen
 
Zitat:

Zitat von Stevie
Generell würde ich es bevorzugen, den Wert nach dem Posten zu erfragen und ihn dann in das RecordSet zu holen, so wie es oben bei MySQL im Moment schon der Fall ist. Dies würde dem insert into ... returning ... into ... von Oracle entsprechen, welches imho die sauberste Lösung ist. Und all das muss in den entsprechenden dbc-units eingebaut werden.

Wie oft muss ich das denn noch schreiben?
Den Oracle Weg gibt es in FB nicht, oder anders ausgrückt: Es gibt keinen wirklich konsistenten Weg um in FB mit autinkrementierten PKs umzugehen.
Was wir hier versuchen werden ist, es wenigstens halbwegs erträglich zu machen. ;)
Zitat:

Zitat von Stevie
Ich sag's hier mal in aller Deutlichkeit:
Ich halte nichts davon, automatisch generierte Werte zum Client zu holen,
um diese wieder in die DB zu schreiben, wenn diese das selber kann!

Wie ich oben schrieb, du musst mit absoluter sicherheit wissen, dass die PK, die du deinem Objekt vergeben hast (oder die einfach nur in einem Datensatz eines DataSets rumliegt) wirklich die ist, mit der du spätere Updates fährst.
FB gibt dir keine andere Möglichkeit als die hier besprochene. Zumindest keine, der ich mir bewusst bin. ;)

Robert_G 14. Jun 2005 21:39

Re: Autowerte bei Firebird setzen
 
Nur damit nicht der Verdacht aufkommt, ich hätte viel Trubel um nüchts gemacht...
Ich bin gerade in einer dieser wochen, in denen man höchsten zum Schlafen nach Hause kommt.
Bis zum WE werde ich aber Zeos ausgecheckt und ein wenig darin gestöbert haben.
Ich hoffe dass ich am WE die Zeit dafür finde. sollte sich ja bestimmt auf <200 Zeilen belaufen.
Mal sehen was man da noch rausholen kann. <g>

mschaefer 14. Jun 2005 22:34

Re: Autowerte bei Firebird setzen
 
Moin, reichlich Spätmoin,

habe mir inzwischen das CVS erstmal installiert, aber das wir hier alle nicht zum Hobby programmieren dürfte wohl inzwischen klar sein. Da sind verzögerungen wohl zu aktzeptieren. Wenn ich das sehe hat Stevie ja schon eine analoge pas - Datei rausgescuht. Komme da aber auch nur nach Feierabend zu, da Zeos doch inzwischen eine gewisse Komplexität erreicht hat.

Fazit: noch dran !

Gute Nacht // Martin


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