Proboha tě prosím, udělej si konečně pořádek v názvech tabulek, názvech polí a názvech datasetů. Ty tam házíš "Master", "Detail", "ID", "FK", "idLandlords", "idFlats", "FKFlat", "Flats", "Landlords" atd. bez jakéhokoliv upozornění, co patří kam. V tom se nedá vyznat, nebo aspoň já se v tom nevyznám - jestli je pole ID v datasetu Detail totožné s polem idLandlords v tabulce Flats nebo jak to vůbec je. Připadá mi, že v každém svém příspěvku to přeházíš, aby to bylo zase úplně jinak. Co kdybys to udělal podle osvědčeného zvyku, že pokud se tabulka jmenuje "Flats", tak její dataset se bude jmenovat "DatasetFlats" (nebo "FlatsDataset", to je mi fuk), a pokud má pole "ID", tak se to pole bude jmenovat "ID" jak v databázi, tak v Delphi? (Pokud to pole má samostatnou komponentu, tak ať se jmenuje FlatsIDField nebo tak nějak, aby bylo jasné, do které tabulky patří.)
Úvaha 1 - tak ako to je napísané (hrám sa na počítač).
Najprv sa dvakrát volá trigger Befor Insert. Nakoľko je podmienka splnená, tak sa 2x spustí generátor. Potom sa dvakrát volá OnBeforePost. Nemá pomienku, tak sa 2x spustí generátor.
Ne, takhle to určitě není. BEFORE INSERT trigger se spouští až v okamžiku, kdy databáze narazí na příkaz INSERT INTO tabulka, což je až poté, co kompletně proběhne BeforePost v Delphi.
Výsledkom je 4x spustený generátor. V skutočnosti sa generátor spustil 3x a v inom poradí. Hľadám ďalej.
3x spuštěný generátor, v souvislosti s posloupností ID v obrázku, značí, že operace proběhnou v tomto pořadí:
1) Proběhne BeforePost na té tabulce, která obsahuje pole FKFlat, ať už to je kterákoliv (v tom aby se prase vyznalo, viz výše). Procedurou se vygeneruje nové ID, které se do toho pole FKFlat zapíše. Primární klíče obou zúčastněných tabulek zůstanou nevyplněné.
2) Proběhne InternalPost do tabulky Flats (odhaduji, viz výše; možná se místo toho jmenuje úplně nesmyslně Detail, fakt nevím). Protože je její primární klíč prázdný, tak se triggerem vygeneruje nová hodnota.
3) Proběhne InternalPost do tabulky Landlords (nebo Master, v tom se prostě nedá vyznat). Protože je její primární klíč prázdný, tak se triggerem vygeneruje nová hodnota.
Úvaha 2 - poznám výsledok a z neho hľadám riešenie
I. Najprv sa vykoná OnBeforePost pre Detail. Prečo? Veď prvý je INSERT! Generuje sa hodnota 601 - OK.
Protože už jsem ti nejméně jednou psal, že BeforePost probíhá ještě předtím, než databázová komponenta vůbec začne uvažovat o tom, že by třeba mohla oslovit databázi - tzn. ještě předtím, než vůbec někdo vymyslí, že výsledkem postu bude nějaký příkaz INSERT INTO tabulka. Ten INSERT se začne řešit až poté, co skončí celý BeforePost - to teprve komponenta vygeneruje příkaz, v tomto případě INSERT, a pošle ho databázi. Databáze přijme INSERT, a protože je to INSERT, tak se podívá, jestli jsou nějaké BEFORE INSERT, které by mohla zavolat. Ty provede, pak spustí samotný insert, a pak spustí všechny AFTER INSERT (pokud nějaké jsou). Pak vrátí řízení volajícímu (tzn. komponentě) a ta zavolá AfterPost. A teprve až AfterPost skončí, tak program bude pokračovat dalším příkazem za Dataset.Post.
II. Nalseduje trigger Befor Insert pre Detail. Generuje sa hodnota 602 - OK. Ale prečo sa generuje ID, keď v OnBeforePost sa zapisuje hodnota pre ID?
Protože to máš blbě pojmenované, tak se v tom nikdo nevyzná. Já si z tvých kódů myslím, že sice vygeneruješ nové ID, ale pak ho zapisuješ do špatného políčka. Varianta 2 je, že ho sice zapisuješ do správného políčka, ale ve špatném pořadí - pokud používáš cizí klíče, tak
musíš napřed zapsat do tabulky, na kterou se budeš odkazovat, a teprve potom zapisovat do tabulky, ze které se odkazuješ (prostě proto, že ten odkaz musí mít platný cíl, což dost dobře mít nemůže, pokud napřed zapíšeš odkaz a teprve potom začneš vytvářet cíl). A ten cíl musí existovat
v databázi - je úplně jedno, že jsi třeba vyplnil DatasetX.FieldY.Value, protože o tom se databáze nedozví, dokud neproběhne Post, a pokud se databáze o něčem nedozví, tak to v té databázi neexistuje!
Aby to tu bylo explicitně: Když zavoláš XXX.Post (kde XXX je TDataset napojený na nějakou SQL databázi), tak proběhnou následující operace (tedy ještě některé další, ale budu psát jen ty, co jsou pro tento problém relevantní):
0) [Aplikace) XXX.Post.
1) [Aplikace] XXX.BeforePost.
2) [Aplikace] XXX.InternalPost. Jeho součástí je:
2.1) [Aplikace] Vygenerovat SQL příkaz do databáze a poslat ho.
2.2) [DBServer] Všechny BEFORE triggery pro operaci v SQL příkazu.
2.3) [DBServer] Vlastní provedení operace v SQL příkazu.
2.4) [DBServer] Všechny AFTER triggery pro operaci v SQL příkazu.
3) [Aplikace] XXX.AfterPost.
4) [Aplikace] Teprve teď se začne zpracovávat další příkaz po XXX.Post.
Je zrejmé, že mi chýba nejaká podstatná vedomosť. Čo to je a kde si o tom môžem prečítať?
Základy jazyka SQL (tohle není Firebirdový problém, tak, jak to děláš, by ti to přesně stejně nefungovalo i s jakoukoliv jinou databází) a nastudovat si trochu, jak funguje posloupnost v TDataset.Post - ideálně tak, že si pěkně prokrokuješ tu komponentu, kterou pro přístup k databázi používáš, ale když na to přijde, tak to klidně můžeš udělat s prehistorickou TTable.