![]() |
Datenbank: Firebird • Version: 2.5 • Zugriff über: FireDAC
FireDAC : Trigger geht nicht
Moin,
will etwas mit FireDac testen und wollte mir deshalb eine Table erstellen.
Delphi-Quellcode:
Die Table enthält natürlich noch eine ID, die über Trigger hochgezählt wird. Lege ich in IBExpert von Hand einen Datensatz an, ähnlich wie hier im Programm, dann wird die nicht eingegebene ID automatisch vergeben, der Trigger scheint also zu gehen. Lasse ich obiges Delphi-Programm laufen, dann kommt allerdings folgende Fehlermeldung : "Das Feld ID muss einen Wert haben". Wieso das ?
DM.DS.Insert;
DM.DS.FieldByName('NR').AsInteger := i + 100; DM.DS.FieldByName('BEZ').AsInteger := i; DM.DS.Post; if i mod 1000 = 0 then begin mem1.Lines.Add(IntToStr (i)); DM.Trans.Commit; DM.Trans.StartTransaction; end; Nachtrag : ersetze ich das Insert durch ein Edit, dann laufen in dem Kontrollmemo schön die Tausender durch, das Feld BEZ bleibt aber bei dem vorher manuell eingegeben Wert. Da wird also in diesem Fall nichts abgespeichert, ohne dass Fehlermeldung kommt. |
AW: FireDAC : Trigger geht nicht
Welche eine Komponente? Wie sieht der Trigger aus?
FireDAC führt keinen Trigger aus, sondern der Server. |
AW: FireDAC : Trigger geht nicht
Zitat:
|
AW: FireDAC : Trigger geht nicht
Hallo Hansa,
zeig mal den Trigger. Was ist wenn du nicht mit Insert/Post arbeitest sondern wie jeder Normale (Spaß :P) eine Query absetzt? |
AW: FireDAC : Trigger geht nicht
Zitat:
Zitat:
|
AW: FireDAC : Trigger geht nicht
Bin mal wieder naiv, was passiert denn bei:
Delphi-Quellcode:
Wenn ID als not null definiert ist, so fehlt beim Insert für die ID natürlich ein Wert. Der Trigger schlägt (vermutlich) erst nach dieser Überprüfung zu.
DM.DS.Insert;
DM.DS.FieldByName('ID').AsInteger := 0; DM.DS.FieldByName('NR').AsInteger := i + 100; DM.DS.FieldByName('BEZ').AsInteger := i; DM.DS.Post; if i mod 1000 = 0 then begin mem1.Lines.Add(IntToStr (i)); DM.Trans.Commit; DM.Trans.StartTransaction; end; |
AW: FireDAC : Trigger geht nicht
Zitat:
![]() ![]() Zitat:
|
AW: FireDAC : Trigger geht nicht
Jetzt zum dritten mal, ein und derselbe Trigger der in IBExtert offensichtlich zuschlägt, schlägt offensichtlich über FireDAC nicht zu.
Code:
Das steht im Trigger, was sonst ? Wenn ich schreibe Table dann ist zumindest aus dem Zusammenhang zu schliessen, dass damit Database-Table gemeint ist und nicht irgendeine Table-Komponente. DM steht übrigens für DataModule und DS für Dataset, bzw. in diesem Fall für FDQuery. Dass es viele FireDac-Komponenten gibt weiss ich auch und ich benutze nicht nur die eine. 8-)
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(GEN_TEST_ID, 1); @nahpets : das habe ich auch schon probiert, also die ID von Hand vergeben. Aber auch dann kommt offensichtlich nichts in der DB an. Fehlermeldung bleibt aber aus. @Uwe : beim Edit ist die ID ja schon da und der Trigger tritt nicht in Aktion, ist ja klar, aber ich ändere doch zumindest die anderen beiden Felder. Auch davon ist nichts zu sehen. Das dürfte alles nicht viel sein, irgendeine dumme Einstellung, aber momentan ein Rätsel. Mir fällt langsam nichts mehr ein, wo ich nachgucken soll :cyclops: |
AW: FireDAC : Trigger geht nicht
Was steht bitte in der Create-Anweisung des Triggers:
Delphi-Quellcode:
Before oder After?
CREATE TRIGGER trigger-name for table-name
[ACTIVE | INACTIVE] {BEFORE | AFTER} <actions> [POSITION number] AS Kannst Du im Trigger irgendeine (wie auch immer geartete) Ausgabe machen, um zu erkennen, ob der Trigger beim Aufruf aus dem Programm überhaupt aktiv wird? Er scheint ja zuweilen zu arbeiten, oder konntest Du schon sicherstellen (dich vergewissern), dass er auf jeden Fall immer aufgerufen wird. Oder: Könntest Du ein (vorübergehendes) Logging in den Trigger einbauen, analog zu ![]() Eigentlich erscheint mir der Trigger korrekt zu sein, er dürfte ja diesem Beispiel entsprechen:
Delphi-Quellcode:
Wenn Du im Trigger eine Exception schmeißt (ohne jede Bedingung, immer und grundsätzlich
create trigger biu_parts for parts
before insert or update as begin /* conditional code when inserting: */ if (inserting and new.id is null) then new.id = gen_id(gen_partrec_id, 1); /* common code: */ new.partname_upper = upper(new.partname); end
Delphi-Quellcode:
, bekommst Du sie aus dem Programm zu sehen? Wenn nein, dann wird der Trigger (höchstwahrscheinlich) nicht immer aufgerufen.
EXCEPTION [<exception-name> [custom-message]]
Allerdings hab' ich überhaupt keine Idee, warum es eine derartige Situation geben sollte. |
AW: FireDAC : Trigger geht nicht
Zitat:
Dann das obligatorische "ist der Stecker drin?", sprich: bist du auch sicher mit derselben Datenbank verbunden? Wenn es machbar ist, lannst du ja auch mal die nötigen Sourcen hier anhängen, damit wir auch was sehen können. :glaskugel: |
AW: FireDAC : Trigger geht nicht
FireDAC erkennt das ID-Feld als Primärschlüssel und fordert daher, dass es einen Wert erhält. Dieser wird aber erst auf dem Server (!) durch Deinen Trigger zugewiesen. Man muss FireDAC also dazu bringen, ein Feld, welches als "required" markiert ist, leer zum Server zu senden. Das geht entweder, indem man es als "AutoInc"-Feld deklariert (siehe Uwe) oder aber, indem man in den Update-Options die Eigenschaft "CheckRequired" auf FALSE setzt.
Bei Deinem Code kommt es gar nicht soweit, dass der Trigger angestossen werden könnte, weil FireDAC den Post-Request als unvollständig betrachtet und ablehnt. Die Daten erreichen den Server nicht einmal. |
AW: FireDAC : Trigger geht nicht
@nahpets : das mit der Exception (für mkinzler : Datenbank-Exception :mrgreen: ) hatte ich schon gemacht und deshalb gesehen, dass der Trigger tatsächlich nicht zuschlägt (natürlich für Insert ein BI-Trigger).
Und die Ursache für den Effekt ist tatsächlich genau das, was Uwe und Daniel angemerkt haben. Ich habe FireDAC eben nicht mitgeteilt, dass die ID ein über Trigger automatisch aktualisiertes Feld ist. Ich habe das jetzt nachgeholt und der ursprüngliche Fehler ist weg. Das haben sie aber trotz der Wichtigkeit unnötigerweise gut in OI-Untermenü versteckt bei Update-Options. Jetzt gibt es aber noch ein ähnliches Phänomen : Zitat:
|
AW: FireDAC : Trigger geht nicht
Hallo,
vielleicht hilft das ja. ![]() Also: Set TField.AutoGenerateValue to arAutoInc for an auto-incrementing field. This method does not create a TFDAutoIncField, it works with any field type, and may require additional field properties setup, like setting ProviderFlags, Required and ReadOnly. Zu spät ... (AutoInc) So, jetzt zeig mal deine Tabellenstruktur. Heiko |
AW: FireDAC : Trigger geht nicht
Tabelle ? Im Prinzip steht die oben schon, egal.
Code:
CREATE TABLE WG8 (
ID INTEGER NOT NULL, NR INTEGER NOT NULL, BEZ VARCHAR(25) DEFAULT '' NOT NULL ); ALTER TABLE WG8 ADD CONSTRAINT UNQ_WG8 UNIQUE (NR); ALTER TABLE WG8 ADD CONSTRAINT PK_WG8 PRIMARY KEY (ID); |
AW: FireDAC : Trigger geht nicht
Hallo zusammen,
ich hoffe, ich darf hier mal kurz "reingrätschen" ;-) : In dem Trigger steht: IF (NEW.ID IS NULL) THEN NEW.ID = GEN_ID(GEN_TEST_ID, 1); ...klingt im Prinzip gut, geht aber schief wenn durch irgendwas (z.B. FireDAC) die ID schon mit 0 (also numerisch 0, nicht dem Zustand NULL) vorbelegt wurde. besser: IF ((NEW.ID IS NULL) or (NEW.ID=0)) THEN NEW.ID = GEN_ID(GEN_TEST_ID, 1); oder auch (macht das selbe, nur etwas kürzer): IF (coalesce(NEW.ID,0) = 0) THEN // coalesce: falls NULL, nimm' das zweite Argument NEW.ID = GEN_ID(GEN_TEST_ID, 1); MMn: Entweder der Trigger in der DB feuert gar nicht (weil durch irgendwas in FireDAC das INSERT gar nicht erst bis zum Server durchkommt), oder er feuert zwar, macht dann aber nichts, weil die ID nicht NULL sondern 0 ist. lg, Frank P.S. gibt es hier so etwas wie einen Thread zur Vorstellung neuer User? ("Neu" bin ich zwar nicht mehr, aber zumindest hier gerade neu... :-D ) |
AW: FireDAC : Trigger geht nicht
Soweit ich informiert bin, haben Trigger in der DB Vorrang vor Client-Triggern. Im konkreten Fall hätte dann der Trigger, der die Id-Erzeugung im Generator anstößt, Vorrang vor dem im Firedac-Query eingestellten Defaultwert. In FireDac gebe ich an, welcher Generator für die Erzeugung des Primary-Key (den ich ebenfalls angebe) zuständig ist. FireDac führt das aber nur aus, wenn in der DB nicht bereits ein Trigger das Setzen dieses Wertes anstößt.
Zitat:
|
AW: FireDAC : Trigger geht nicht
Zitat:
2. das mit der ID ist schon geklärt, der Trigger scheint schon zu feuern. In externem IBExpert (bereits ca. 5mal gesagt) macht er das ja sowieso, aber auch in anderem eigenem Programm (allerdings mit FibPlus als Zugriffskomponenten) 3. Die Frage dreht sich nur noch darum, warum jetzt plötzlich der unique Key Ärger macht. Muss man das eventuell ähnlich einstellen, wie mit dem AutoInc-Feld ? Oder hängt das gar zusammen ? Ich sehe aber da nichts in FireDac, was irgendwie in diese Richtung gehen könnte. 4. Wie gesagt : bei leerer Tabelle schlägt der Insert fehl mit NR, die es noch gar nicht gibt. Und NR hat mit der ID nichts zu tun. Ist halt lediglich unique, was mein Programm besser sowieso der Datenbank im Fehlerfalle überlassen sollte. @Perlsau : Davon ging ich auch aus. Der DB muss aber offensichtlich das als AutoInc zu behandelnde Feld mitgeteilt werden. Die Frage lautet jetzt also, was FireDac da weshalb genau macht. Warum interessiert sich FireDac überhaupt um einen unique Key ? Trigger/ID ist vorerst erledigt ! Also nochmals : der Trigger geht definitiv richtig ! Und der nicht vorhandene unique landet nicht in der DB wegen
Code:
Die Nr. 101 ist doch gar nicht da !
Problematic Key is ("NR" = 101
|
AW: FireDAC : Trigger geht nicht
geth die Meldung noch weiter? Ich seh da "(" auf nicht zu. Ist die Nummer 101 vollständig oder ist da was abgeschnitten?
Mit welcher Aktion erzeugst Du diesen Fehler? Offenbar ja mittels Delphiprogramm. Welche Werte stehen vor dem Post im Record? Ist "Nr" belegt oder leer? Leer sollte es nicht sein, da es not null definiert ist. |
AW: FireDAC : Trigger geht nicht
Sicher, dass die 101 noch nicht da ist?
Ausgehend von den Quelltextfragmenten, kann es die 101 nur einmal geben. Zumindest gehe ich mal davon aus, dass du da eine For-Schleife mit sowas wie
Delphi-Quellcode:
hast. Wenn dem so ist, warum wird dann nicht schon bei Nr. 100 gemoppert?
for i := 0 to n
Wenn i bei 1 beginnt, hieße das aber, dass bereits der erste Satz als Schlüsselverletzung angesehen wird. Dies erscheint mir dann aber doch ziemlich schräg, könnte aber bedeuten, dass irgend etwas konfigurationstechnisch dafür sorgt, dass jeder Datensatz mindestens zweimal (aus Sicht der Datenbank) dort ankommt. Was passiert, wenn Du (vorerst) nach jedem Satz mal ein Commit machst? Quasi
Delphi-Quellcode:
Zumindest müsstest Du bei einem satzweisen Commit ja dann nachschauen können, ob schon 'ne 101 da ist. Wenn nicht, dann muss das Problem bei FireDac liegen.
if i mod 1 = 0 then begin
Eventuell könntest Du den Quelltext mal ein bisserl umbauen:
Delphi-Quellcode:
Wie oft bekommst Du hier i = 1 zu sehen? Denn das müsste ja eigentlich zu dem Fehler führen.
DM.DS.Insert;
DM.DS.FieldByName('NR').AsInteger := i + 100; DM.DS.FieldByName('BEZ').AsInteger := i; try DM.DS.Post; except on e : Exception do begin DM.DS.Cancel; mem1.Lines.Add(Format('i = %d - %s'[i,e.Message])); end; end; Zugegeben sind mein Vorschläge gerade nur reines stochern im Nebel, darfst sie von daher gerne ignorieren ;-) |
AW: FireDAC : Trigger geht nicht
Hallo zusammen,
@Hansa: ich bin da "gebranntes Kind": wenn <irgendwas> mit IBExpert geht, dann heißt das noch lange nicht, dass es mit Firebird per se geht... (sorry, Holger... ;-) "Der Trigger scheint zu feuern"... Vergiss' das. Lege einen neuen Generator an, der NUR im Trigger erhöht wird. Wenn der nach deinem Test erhöht wurde, dann wurde der Trigger gefeuert. Sonst nicht. ("Generators run outside of transaction control!") (Ob die Transaktion danach dann vlt. einem Rollback zum Opfer gefallen ist, weisst Du dann aber immer noch nicht ;) ) Die Sache mit dem Unique Key ist noch mal eine ganz andere Baustelle. Ohne das Umfeld genauer zu kennen, kann ich nur mutmaßen: wenn die DB meckert, daß es zum Zeitpunkt des Inserts schon einen Datensatz mit NR=<x> gab, dann wird das wohl so gewesen sein... ;) Vlt. noch eine andere Instanz des Programms? Nicht-COMMITtete Transaktion? Die Transaktionen in Fb funktionieren, dafür lege ich meine Hand in's Feuer(!). Die Generatoren/Sequenzen auch. Wenn im Zusammenspiel zwischen Programm und Fb-Server etwas nicht funktioniert, liegt das Problem erfahrungsgemäß irgendwo in der Mitte ;) lg, Frank |
AW: FireDAC : Trigger geht nicht
Zitat:
Delphi-Quellcode:
Danach ist alles auskommentiert, was eigentlich geplant war. Jetzt kommt noch der Witz : Habe das Unique-Key-Feld Nicht-unique gemacht und der Fehler ist nicht weg ! Ok, Datenbank fast leer gemacht und immer noch dasselbe. Näcgster Ansatz wäre dann die DB an sich. Gibt ConnectionName da vielleicht falsche Namen zurück ? Die lasse ich mir nämlich vorsichtshalber anzeigen. Und sie beziehen sich auch auf die zu bearbeitende DB.
i := 0;
Wäre ja naheliegend, dass ich die falsche benutze. Sehe das aber nicht so. |
AW: FireDAC : Trigger geht nicht
Moment, nochmal zum Mitschreiben. Du machst also nur noch das:
Delphi-Quellcode:
und das scheitert beim ersten Datensatz in eine leere Tabelle mit einer Schlüsselverletzung im Feld Nr in einer Tabelle, die für das Feld Nr keinen eindeutigen Schlüssel hat?
i := 0;
DM.DS.Insert; DM.DS.FieldByName('NR').AsInteger := i + 100; DM.DS.FieldByName('BEZ').AsInteger := i; DM.DS.Post; 1. Drop Table und neumachen. 2. Erneut probieren, Fehler weg? 3. Wenn nein, neue Datenbank machen, nur diese Tabelle und den Trigger und erneut probieren. 4. Fehler weiter da? Rechner ausschalten und morgen erneut probieren ;-) Nein, ehrlich gesagt keine Ahnung. Gibt es irgendeinen Cache, der Daten vorhält..., so dass das Programm irgend etwas "aus der Vergangenheit" sehen könnte, was in der Realität nicht mehr existiert? Aber dann dürfte ja die Datenbank nicht meckern. Gibts da 'nen Clone von, auf den Du noch (irrtümlich) zugreifst? Entwicklungsumgebung mal zugemacht? Datenbank neu gestartet? Neues, leeres Projekt mit nur dem Datenbankzugriff und dem Insert in diese Tabelle (nicht per Copy&Paste aus dem "alten" Projekt übernehmen, wer weiß, was jetzt da nicht stimmt)? Kenne FireDac nicht (mein Delphi ist zu alt), gibt es denn da die Möglichkeit etwas so stark zu "verkonfigurieren", dass daraus ein derartiges Problem resultieren könnte? Glaube nicht, dass ich hierzu noch irgendwas halbwegs sinnvolles schreiben könnte :-( |
AW: FireDAC : Trigger geht nicht
Hansa, ich seh da nur das eine Problem aus deinem Eingangsposting:
Zitat:
In solchen Fällen erhalte ich ebenfalls eine Fehlermeldung, das kann nicht funktionieren. Du legst ja auch den Wert des PrimaryKeys nicht im Client fest, wenn du dafür in der DB ebenfalls einen Trigger hast, der bereits reagiert, bevor die vom Client gesendeten Daten eingetragen werden. Laß also einfach die Zuweisung an das Feld NR im Client weg und du hast dieses Problem nicht mehr. |
AW: FireDAC : Trigger geht nicht
Hallo,
das Autoinc-Feld ist aber ID, nicht NR ... Heiko |
AW: FireDAC : Trigger geht nicht
Hallo Hansa,
mache doch einfach mal ein
Code:
Wie schon gefragt. (Antwort vieleicht überlesen) Wird der Generator erhöht wenn dein Fehler kommt?
FireDacQuery.SQL.Text:= 'insert into TABLE (NR,BEZ) values (:nr,:be)'; // vor der Schleife -> nur einmal zuweisen. Macht bei den heutigen Rechnern kaum einen Unterschied.
FireDacQuery.ParamByName('nr').AsInteger:= i + 100; //die Parametersyntax könnte ggf. abweichen FireDacQuery.ParamByName('be').AsInteger:= i; FireDacQuery.ExecSQL; |
AW: FireDAC : Trigger geht nicht
Zitat:
Aber ließe sich der obige Code nicht noch erweitern, in dem man immer eher sowas macht:
Delphi-Quellcode:
Hier werden dann halt immer 1000 Inserts an einem Stück an die Datenbank gegeben und von ihr verarbeitet, statt satzweise. Hab' sowas in de Art vor Jahren mal bei 'ner SQL-Server-Datenbank gemacht, dass hat bei der zu verarbeitenden Datenmenge etliche Stunden Zeitersparnis gebracht.
sSQL := 'insert into TABLE (NR,BEZ) values (%d,%s);';
DM.Query.SQL.Clear; DM.Trans.StartTransaction; for i := 1 to n do begin DM.Query.SQL.Add(Format(sSQL,[i + 100,QuotedStr(i)])); if i Mod 1000 = 0 then begin DM.Query.ExecSQL; DM.Trans.Commit; mem1.Lines.Add(IntToStr(i)); DM.Query.SQL.Clear; DM.Trans.StartTransaction; end; end; |
AW: FireDAC : Trigger geht nicht
Zitat:
( ![]() |
AW: FireDAC : Trigger geht nicht
@Daniel
Das ist doch eine absolut elegante Lösung. |
AW: FireDAC : Trigger geht nicht
mal zurück zur eigentlichen Problematik
Datasets, die für Delphi und Firebird entwickelt wurden, wie zum Beispiel IBObjects, haben Properties, mit denen man den verbundenen Generator festlegen kann. Das heisst dann bei IBO z.B. KeyGeneratorLink o.ä. Da man in Firebird selbst entscheiden kann, welcher Generator pro Tabelle benutzt wird, ist dieser Weg sehr praktisch, denn bei mir gibt es für alle Tabellen immer nur einen Generator, aus dem alle ID Werte geholt werden. Nun kommen aber mehr generalisierte Komponenten wie Firedac nicht mit jeder unterstützten Plattform zu 100% klar. Mein Tip: Verliert euch nicht in der Abhängigkeit zu einer Komponente. Wie oben schon erwähnt bekommt Firebird noch gar nicht mit, das es einen Insert geben sollte, wenn auf Ebene der Delphi Komponente Bedingungen noch gar nicht erfüllt sind. Man könnte das als Mangel der FireDac Komponenten im Zusammenspiel mit Firebird betrachten oder einfach mal in den Dataset Events nach OnNewRecord suchen. Wenn Ihr im OnNewRecord Ereignis dann ein SQL startet "select gen_id(genid,1) from rdb$database" und den Rückgabewert in euer Primärschlüsselfeld übertragt, werdet Ihr feststellen, das es gar nicht so schwer ist, selbst die Kontrolle über solche Vorgänge zu haben. Wenn Ihr ein Generator pro Tabelle habt, könntet ihr das auch dynamisch machen, weil im Event ja der Sender(also das Dataset) kommt und das ja hoffentlich properties hat, aus denen sich der Tabellenname ergibt. Und wenn Ihr das Event nicht für jedes Dataset manuell neu setzen wollt, könnt Ihr mit sehr wenig Aufwand auch ein global benutzbares Event dafür im Datenmodul generieren und das ggf. jedem Dataset in der components List im OnCreate zuweisen. Oder noch viel cleverer, einfach eine Ableitung der benutzten Dataset Klasse machen, in dem das automatisch passiert. Wichtig: Nur weil Firebird und FireDAC vorne vier gleiche Buchstaben haben, ist FireDAC keineswegs die erste Wahl für Firebird und Delphi. |
AW: FireDAC : Trigger geht nicht
Zitat:
Damit sind auch aus Delphi heraus bis zu 10000 Inserts pro Sekunde in die Firebird DB machbar. |
AW: FireDAC : Trigger geht nicht
Zitat:
Aber egal. FireDac beschwert sich immer noch beim Einfügen eines unique Key-Felds. Offensichtlich wird immer nur auf den Titel geantwortet und nicht im Kontext. :shock: Ich werde das Problem deshalb jetzt reduzieren. Neue Datenbank anlegen mit einer Table und dann mal sehen. Da sich dadurch wohl nichts ändern wird, werde ich gegebenenfalls neues Thema aufmachen. Dürfte nicht lange dauern. :mrgreen: Wenns endlich geht, befülle ich die DB mit FireDac dann mal neu. Das Daniel-Array und die Überlegungen von Holger Klemt werde ich dann eventuell auch einbauen. Mein Generator (es gibt nur einen) steht bei ca. 2.000.000. 10.000 Einfügeoperationen pro Sek. wär natürlich schon gut. |
AW: FireDAC : Trigger geht nicht
Hallo Hansa,
wie schon gesagt: wenn Firebird meckert, dass es die Nr. 101 schon gibt, dann ist das so(!). Wenn die Tabelle beim Start wirklich leer ist, dann kann das eig. nur daran liegen, dass zwei Insert-Befehle mit der gleichen NR nacheinander abgesetzt werden. Am besten mal in die MON$-Tabellen im Firebird schauen oder mit einem Trace-Tool (z.B. Thomas Steinmaurer's Fb Tracemanager) nachsehen, was *wirklich* im Server ankommt. Nur so kannst Du irgendwelche "behind the scene magic" in FireDAC ausschliessen. Hi Holger, ( lange nicht gesehen :wink: ) ich stimme Dir in allen Punkten zu. Nur noch ein Hinweis dazu: Wenn man mit der EXECUTE BLOCK-Methode arbeitet, sollte man trotzdem jeden Generatorwert per "select gen_id..." aus der DB holen. Es kamen schon mal Leute auf die Idee, die IDs Client-seitig hochzuzählen und anschließend mit SET GENERATOR den Generator in der DB auf den zuletzt vergebenen Wert zu setzen, oder sich mit "select gen_id(genid,1000) from rdb$database" mal eben 1000 Generatorwerte auf einen Schlag zu "reservieren". Beides funktiniert aber nur, wenn man exklusiven Zugriff auf die DB hat - sobald mehrere User oder Programminstanzen an der DB hängen, die das u.U. gleichzeitig machen können, kann das furchtbar schiefgehen... immer dran denken, dass Generatoren außerhalb jeder Transaktions-Kontrolle arbeiten! :thumb: lg, Frank |
AW: FireDAC : Trigger geht nicht
Moin, Frank,
jo, volle Zustimmung, aber in der ID Spalte brauchst du ja auf dem Weg über execute block gar nichts eintragen und kannst die einfach weglassen, denn da greift ja ggf. der auf der Tabelle definierte Autoinc Trigger und eine Zugriffskomponente brauch sich da auch nicht einmischen. Von einem früheren Projekt, wo der Kunde mit Informix gearbeitet hat, weiss ich noch von einem Bug, der erstmalig nach ca 9 Monaten Echtbetrieb aufgetaucht ist. Die Primärschlüssel und damit auch die Fremdschlüssel für Details wurden immer aus Nummernkreistabellen geholt. Dabei nutzte man ein Verfahren, was angeblich auch im Multiuserbetrieb mit Informix sicher war. Dummerweise ist da nach 9 Monaten mal jemandem in der Logistik ein Lieferschein aufgefallen, auf dem keine Positionen waren. Der Mitarbeiter hat den also so abgearbeitet und eben nichts geliefert, den Lieferschein aber erst abends seinem Vorgesetzten vorgelegt. Dieser hat dann am Folgetag in der Fachabteilung nachgefragt, weil laut Auftragsbearbeitung sollte da auch was geliefert werden. Ein wenig Recherche und schon stellte man fest, das die Positionen dummerweise auf einen anderen Lieferschein gebucht wurden, der für einen anderen Kunden war und schon ausgeliefert wurde. Auf Nachfrage bei dem Kunden hatte der sich dann auch schon gewundert, was da geliefert wurde, weil er dazu wiederum auch keine Bestellungen finden konnte. Der Vorgang Lieferschein anlegen war ein Modul in der im Haus selbst programmierten Software und dort wurde dann einfach mal der Wert aus der Tabelle mit den Nummern ausgelesen, aber beim schreiben der Erhöhung um 1 war da der allseits beliebte try ... except {mir doch egal} end; drumherum, also im Falle einer Exception wird nix gemacht. Da sich also wohl erstmals nach 9 Monaten Echtbetrieb zwei Buchungen in die Quere kamen, rächte sich diese Schlampigkeit. Da auch noch die Lieferscheinnummer als Fremschlüssel genommen wurde (und nicht ein rein technischer Wert wie zum Beispiel die von allen Firebird Programmierern bevorzugten Generatorwerte, die mit 64 Bit reichlich Platz bieten), wurden daher wohl die Detailbuchungen vom Client dem falschen Kopf zugeordnet. Oder mit anderen Worten, diverse Paletten wurden kreuz und quer durch die Gegend sinnlos hin- und zurück gefahren, weil ein Programmierer da ein ungeeignetes Verfahren gewählt hat. Im Nachhinein ist dann wohl jemandem noch aufgefallen, das wohl schon häufiger vorkam, aber wohl bisher noch nie ein komplett leerer Lieferschein erzeugt wurde. Wie ich und Frank und viele andere sicher auch bestätigen können, ist der Weg über den Trigger und Gen_id() bzw. direkt über Gen_id() der einzig richtige Weg für Firebird, um netzwerksicher und transaktionssicher bei der Primärschlüsselerzeugung zu sein. Ich für meinen Teil benutz dabei dann auch noch einen einzigen Generator für alle Tabellen, was diverse weitere Vorteile hat. Da es diese Konstrukte aber bei anderen Datenbanksystemen nicht gibt, muss eine Komponentenbliothek wie FireDAC dann eben auch unter Berücksichtigung der TDataset Kompatibilität da diverse Kompromisse und Workarounds machen. Ich für meinen Teil arbeite mit TDatasets im Insert/Edit/append/post Verfahren schon seit 10 bis 15 Jahren nicht mehr freiwillig (ist aber von der Höhe des Honorars abhängig), weil ich der Datenbank in SQL Sprache sage, was ich von der will und Datasets nur zum Lesen für select Ergebnisse benutze. |
AW: FireDAC : Trigger geht nicht
Moin,
was FireDAC da macht, ist weder ein Kompromiss noch ein Workaround. Entweder verbindest Du das PK-Feld mit dem Generator und hast den Wert dann schon direkt nach dem Append/Insert, sofern Du ihn da benötigst oder Du stellst die Komponente so ein, dass Du das PK-Feld leer absenden kannst. In jedem Fall wird der Entwickler gezwungen, sich mit der Frage zu befassen, damit z.B. solche wie von Holger geschilderten Fehler nicht passieren. |
AW: FireDAC : Trigger geht nicht
Hallo Hansa...:roll:
probiere doch einfach mal die einfache Query. Da wirst du sehen das das funktioniert. Das Problem liegt zu 99.99% wie schon mehrfach gesagt an den Einstellungen der Table die du verwendest und nicht am eigentlichen Trigger der DB. Für das Layer 8 Problem gleich die Komponenten madig zu machen ist nicht nett. :P |
AW: FireDAC : Trigger geht nicht
Moin,
ich habe doch nicht rumgemosert. Lediglich angemerkt, dass manche Sachen nicht da sind, wo man sie erwarten würde und vom Namen her auch der Zweck nicht direkt erkennbar ist. Deshalb ist manches schlecht zu finden. Nachdem Dank Daniel klar war, warum die ID Ärger macht, dann aber ging, hatte ich mir nochmals die Update-Options angesehen, weil der unique Key ja auch anfangs nicht ging. Und siehe da, da gibts KeyFields. Was das bei UpdateOptions zu suchen hat, obwohl das ja auch nur zum Lesen gebraucht wird, führt einen in die Irre. Immerhin : das Wort Key ist auch im "unique Key" zu finden. Da habe ich dann das Feld NR eingetragen und dann ging auch das. Ich habe also grob geschätzt ca. 6 St. gebraucht für : Komplette neue DB anlegen, samt Triggern und Keys mit IBExpert. Da mir ja nicht geglaubt wurde, dass der Trigger auf DB Seite geht bzw. das einfach überlesen/ignoriert wurde, habe ich unnötig viel Zeit in die Überprüfung des Triggers investiert. In Delphi habe ich dann noch Datamodul mit dem FireDAC Zeugs angelegt und das alles soweit richtig eingestellt. Viel lesen in der Hilfe kam noch dazu und jetzt kommt noch noch etwas zum meckern : Aber eher an Emba : nicht nur bei den Update Options sagt mir die Hilfe folgendes :
Code:
Man muss aber mehr fragen/suchen als unbedingt nötig.
Embarcadero Technologies verfügt zurzeit über keine zusätzlichen Informationen. Bitte unterstützen Sie uns bei der Dokumentation dieses Themas, indem Sie Ihre Kommentare auf der Diskussionsseite eingeben.
Das eigtliche Delphi-Testprogramm habe ich ja auch noch gemacht und getestet. Jedenfalls bin ich mit sechs St. Aufwand zufrieden. Jemand, der sich weniger auskennt, der hätte wohl eher 6 Tage gebraucht und ein blutiger Anfänger sogar 6 Wochen. |
AW: FireDAC : Trigger geht nicht
Und hättest Du jetzt noch den Debugger und den SQL-Monitor verwendet ...
|
AW: FireDAC : Trigger geht nicht
Für FireDAC oder was ?
|
AW: FireDAC : Trigger geht nicht
Ja.
|
AW: FireDAC : Trigger geht nicht
Ab und an muss man ein wenig klicken, aber hier sind die Optionen allesamt aufgelistet:
![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz