Autor Téma: Získanie práve vytvoreného ID  (Přečteno 18275 krát)

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 7430
  • Karma: 44
    • Verze Delphi: W11 + D11.3.1
Získanie práve vytvoreného ID
« kdy: 25-10-2012, 08:56:42 »
ID = hodnota pre Primary key

Čo riešim
Vytvorím nový záznam - je už v tabuľke. Aktualizujem si VT - hodnotami z formulára, ale tam nemám ID. Tým pádom pri pohybe vo VT mi nenájde patričný záznam (TIBDataset.Locate('ID', ...)). Ako správne získať hodnotu ID? Predpokladám konkurečný prístup k tabuľke.

Čo som sa dočítal

1) Použiť uloženú procedúru a ziskané ID použiť pre primárny kľúč (to sa môže vykonať priamo v SP) a iné účely. Veľmi to neodporúčajú (Císař). ID by sa malo priraďovať pomocou spúšte.

2) Využiť jednoriadkovú systémovú DB. Vytvoriť si tam jeden záznam s ID a vyzdvihnúť si jeho hodnotu na ďalšie použitie. To mi pripadá dosť komplikované.

Podľa toho čo som čítal, tak predpokladám, že TIBDataset po vytvorení záznamu znova načíta všetky údaje. Tam by sa teorteicky dala zistiť hodnota ID podľa najvyššej hodnoty. Ale je to 100 %? Nezdá sa mi to ako pravé orechové.

Jedná sa o vkladanie jednotlivých záznamov na klientovi. Užívateľ musí minimálne stlačiť tlačidlo "Ulož".

Ako sa to správne robí?

 
Win11 64b, Delphi 12.2, FireBird 4.01
Expert na kladenie nejasne formulovaných otázok.

Offline Mi.Chal.

  • Guru
  • *****
  • Příspěvků: 577
  • Karma: 25
Re:Získanie práve vytvoreného ID
« Odpověď #1 kdy: 25-10-2012, 09:33:11 »
měl bys mít někde nějakou logiku, která založí nový záznam a vrátí jeho id. Třeba tak, že si to napíšeš jako SP a ta to id vrátí. Jestli na FB jde nějak nastavit hodnotu v triggeru a vrátit jí v rámci insertu nevím, moc bych tomu ale nevěřil. Jestli tu hodnotu id bude plnit insert nebo si ji vygeneruješ generátorem a použiješ pro vložení insertu je podle mě jedno, pokud máš zaručeno, že ten generátor nebude vracet dvakrát po sobě stejnou hodnotu. Po vložení záznamu si prostě refreshni grid a id záznamu budeš vědět.

2) je blbost, protože to nebude fungovat ve víceuživatelském prostředí. Můžeš dostat tabulku s x záznamy a nevíš, co si vložil ty a co někdo jiný.

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1574
  • Karma: 37
    • Pepak.net
Re:Získanie práve vytvoreného ID
« Odpověď #2 kdy: 25-10-2012, 09:43:32 »
Jestli na FB jde nějak nastavit hodnotu v triggeru a vrátit jí v rámci insertu nevím, moc bych tomu ale nevěřil.
Zničte nevěřící! :-)
INSERT INTO ... RETURNING ...

Citace
pokud máš zaručeno, že ten generátor nebude vracet dvakrát po sobě stejnou hodnotu.
To je u SQL generátorů zaručeno.
Na získání ID předem není nic špatného. Doporučení nebo nedoporučení je spíš věcí zvyklostí autora nebo jím používaného frameworku než nějakých objektivních faktů.

Citace
2) je blbost, protože to nebude fungovat ve víceuživatelském prostředí. Můžeš dostat tabulku s x záznamy a nevíš, co si vložil ty a co někdo jiný.
Plus je blbost pracně emulovat funkci generátorů, které jsou právě pro tohle určené...

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 7430
  • Karma: 44
    • Verze Delphi: W11 + D11.3.1
Re:Získanie práve vytvoreného ID
« Odpověď #3 kdy: 25-10-2012, 10:23:06 »
// INSERT INTO ... RETURNING ...
Za momentálenj siutácie nemôžem použiť. ID zapisujem pomocou generátora v trigger-te v onBeforeInsert. V Insert nemôžem menovať ID, nakoľko musí mať hodnotu null. Viď podmienka v trigger-te  if (new.id is null) then.

2)
//je blbost, protože to nebude fungovat ve víceuživatelském prostředí. Můžeš dostat tabulku s x záznamy a nevíš, co si vložil ty a co někdo jiný.
Asi ti ušlo, že to je jednoriadková tabuľka - vždy! A slúži na podobné účely. Vložíš a okamžite získaš hodnotu. Či tam niekto stačí vložiť nový záznam neviem

// Plus je blbost pracně emulovat funkci generátorů, které jsou právě pro tohle určené...
Vkladá sa to práve pomocou generátora. Slúži to len na získanie práve vygenerovanej hodnoty.

Takže pravdepodobne mám použiť postup

Vytvorím SP, ktorá vygeneruje ID. Spustím ju v trigger-te. Tam hodnotu ID priamo použijem a pomocou SP si ju pošlem na klienta.
Hm, ale keď SP automaticky spustím v trigger-te, ako sa dostanem k návratovej hodnote? To by som vedel pomocou TIBStoredprocedure. Čosi nesedí  :-\
Win11 64b, Delphi 12.2, FireBird 4.01
Expert na kladenie nejasne formulovaných otázok.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3534
  • Karma: 139
    • Verze Delphi: D2007, XE3, DX10
Re:Získanie práve vytvoreného ID
« Odpověď #4 kdy: 25-10-2012, 10:54:17 »
// INSERT INTO ... RETURNING ...
Za momentálenj siutácie nemôžem použiť. ID zapisujem pomocou generátora v trigger-te v onBeforeInsert. V Insert nemôžem menovať ID, nakoľko musí mať hodnotu null. Viď podmienka v trigger-te  if (new.id is null) then.
Ja to teda nezkousel, protoze nove zaznamy vkladame temer vyhradne pres SP mimo operace s datasetem, ale zkousel jsi .... RETURNING :ID?
U nekterych DB s autoinkrementem jsou platna ID > 0, takze v duchu stejne logiky muzes rict, ze ID=0 ma stejny vyznam jako NULL a pak v tom triggeru muzes testova (new.id is null or new.id=0).  Tim by ti mohlo upadnout rada problemu s datasetem.

Vytvorím SP, ktorá vygeneruje ID. Spustím ju v trigger-te. Tam hodnotu ID priamo použijem a pomocou SP si ju pošlem na klienta.
Hm, ale keď SP automaticky spustím v trigger-te, ako sa dostanem k návratovej hodnote? To by som vedel pomocou TIBStoredprocedure. Čosi nesedí  :-\
Ta SP se vetsinou dela na vlozeni zaznamu a vraci nove ID. A v te SP si ID bud vygenerujes dopredu pomoci gen_id a priradis hodnotu do ID a vratis ji z te SP, nebo to nechas na triggeru, u insertu pouzijes to returning :ID a vratis ho z SP.

A nebo zadnou SP delat nebudes a gen_id si spustis na strane klienta normalnim selectem.

Jak psal Pepak, v zasade je to jedno, pro co se rozhodnes, ale v tom konkretnim projektu to pak delej vsude stejne.

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1574
  • Karma: 37
    • Pepak.net
Re:Získanie práve vytvoreného ID
« Odpověď #5 kdy: 25-10-2012, 11:08:07 »
// INSERT INTO ... RETURNING ...
Za momentálenj siutácie nemôžem použiť. ID zapisujem pomocou generátora v trigger-te v onBeforeInsert. V Insert nemôžem menovať ID, nakoľko musí mať hodnotu null. Viď podmienka v trigger-te  if (new.id is null) then.
Hodnota klíče v okamžiku spouštění INSERTu nijak nesouvisí s možností nebo nemožností použít RETURNING. Aspoň si vygoogluj, co ti někdo poradí, když už nechceš číst všechny ty Release Notes.

Citace
2)
//je blbost, protože to nebude fungovat ve víceuživatelském prostředí. Můžeš dostat tabulku s x záznamy a nevíš, co si vložil ty a co někdo jiný.
Asi ti ušlo, že to je jednoriadková tabuľka - vždy! A slúži na podobné účely. Vložíš a okamžite získaš hodnotu. Či tam niekto stačí vložiť nový záznam neviem
Co budeš dělat v okamžiku, kdy si dva lidi současně vyžádají nové ID?
Co budeš dělat v okamžiku, kdy dva lidi současně udělají INSERT (s různým ID)?

Citace
// Plus je blbost pracně emulovat funkci generátorů, které jsou právě pro tohle určené...
Vkladá sa to práve pomocou generátora. Slúži to len na získanie práve vygenerovanej hodnoty.
Viz druhá otázka výše. Pokud už chceš získávat vygenerovanou hodnotu se zárukou, že ti to čas od času vrátí špatné ID, tak používej SELECT MAX(id) FROM tabulka nebo SELECT GEN_ID(generátor, 0) FROM rdb$database - nebudeš kvůli tomu muset vytvářet extra databázové objekty. Já ovšem doporučuju spíš ten RETURNING, protože preferuji, když mi aplikace funguje vždy a ne jen někdy.

Offline Petr P.

  • Nováček
  • *
  • Příspěvků: 29
  • Karma: 1
    • Verze Delphi: Turbo Delphi 2006
Re:Získanie práve vytvoreného ID
« Odpověď #6 kdy: 25-10-2012, 11:15:32 »
Citace
SELECT GEN_ID(generátor, 0) FROM rdb$database
Tohle nefunguje vždy ?

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3534
  • Karma: 139
    • Verze Delphi: D2007, XE3, DX10
Re:Získanie práve vytvoreného ID
« Odpověď #7 kdy: 25-10-2012, 11:16:32 »
Co budeš dělat v okamžiku, kdy si dva lidi současně vyžádají nové ID?
Co budeš dělat v okamžiku, kdy dva lidi současně udělají INSERT (s různým ID)?
Tyhle problemy vyresi snad transakce s vhodnou izolaci, ne?

Offline Mi.Chal.

  • Guru
  • *****
  • Příspěvků: 577
  • Karma: 25
Re:Získanie práve vytvoreného ID
« Odpověď #8 kdy: 25-10-2012, 11:28:37 »
Jestli na FB jde nějak nastavit hodnotu v triggeru a vrátit jí v rámci insertu nevím, moc bych tomu ale nevěřil.
Zničte nevěřící! :-)
INSERT INTO ... RETURNING ...

Jasně, ale to je vracení z insertu, ne z triggeru - prostě tu hodnotu vrací něco jiného, než ji vygenerovalo. Což tady nijak vadit nebude, jenom není nikde patrná ta logika za tím.

Offline Mi.Chal.

  • Guru
  • *****
  • Příspěvků: 577
  • Karma: 25
Re:Získanie práve vytvoreného ID
« Odpověď #9 kdy: 25-10-2012, 11:30:41 »
Co budeš dělat v okamžiku, kdy si dva lidi současně vyžádají nové ID?
Co budeš dělat v okamžiku, kdy dva lidi současně udělají INSERT (s různým ID)?
Tyhle problemy vyresi snad transakce s vhodnou izolaci, ne?

pak se ale budou "zbytečně" zamykat a čekat na sebe, což zas bude mít dopad na výkon.

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1574
  • Karma: 37
    • Pepak.net
Re:Získanie práve vytvoreného ID
« Odpověď #10 kdy: 25-10-2012, 11:34:23 »
Citace
SELECT GEN_ID(generátor, 0) FROM rdb$database
Tohle nefunguje vždy ?
Ne.

Co budeš dělat v okamžiku, kdy si dva lidi současně vyžádají nové ID?
Co budeš dělat v okamžiku, kdy dva lidi současně udělají INSERT (s různým ID)?
Tyhle problemy vyresi snad transakce s vhodnou izolaci, ne?
No tak může, jistě. Sice mi to připadá jako pronajmout si kamion, když potřebuju přenést tři cihly z jednoho rohu zahrádky do druhého, ale ano, problém to také vyřeší...

Jasně, ale to je vracení z insertu, ne z triggeru - prostě tu hodnotu vrací něco jiného, než ji vygenerovalo. Což tady nijak vadit nebude, jenom není nikde patrná ta logika za tím.
To mi přijde trochu akademické - ten trigger se bez obalujícího INSERTu nespustí, a konec konců ani programátorovi asi tolik nezáleží na tom, kde přesně se to ID vytvoří (jestli v triggeru - a kterém z toho tisíce, které na tabulce má - nebo třeba ještě na straně klienta při přípravě dat), hlavně když dostane to ID, které vytvořil. Ale budiž.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 7430
  • Karma: 44
    • Verze Delphi: W11 + D11.3.1
Re:Získanie práve vytvoreného ID
« Odpověď #11 kdy: 31-10-2012, 11:25:16 »
No hurá. Narazil som na nasledovné. Tretí a štvrtý bod ma okamžite zabavili všetkých mukov :)

1. Create a trigger similar to the following.

Kód: [Vybrat]
Create Trigger COUNTRY_INSERT for COUNTRY
active before Insert position 0
as
begin
  if (new.Pkey is NULL) then // Doplnil som o or (new.Pkey = 0)
    new.Pkey = gen_id(COUNTRY_GEN,1);
end^

2. Create a stored procedure that returns the value from the generator:

Kód: [Vybrat]
Create Procedure COUNTRY_Pkey_Gen returns (avalue INTEGER)
as
begin
  avalue = gen_id(COUNTRY_GEN,10);
end^

3. Add a TStoredProccomponent to your application and
associate it with the COUNTRY_Pkey_Genstored procedure.

4. Add a TQuerycomponent to your application and add the following code to
the BeforePostevent:

Kód: [Vybrat]
If(TQuery.state = dsinsert) then
begin
  StoredProc1.ExecProc;
  TQuery.FieldByName('Pkey').AsInteger :=
    StoredProc1.ParamByName('avalue').AsInteger;
end;

This solution allows the client to retrieve the generated value from the server using a
TStoredProccomponent and an InterBase stored procedure. This assures that the
client will know the primary key value when a record is posted.
Win11 64b, Delphi 12.2, FireBird 4.01
Expert na kladenie nejasne formulovaných otázok.

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1574
  • Karma: 37
    • Pepak.net
Re:Získanie práve vytvoreného ID
« Odpověď #12 kdy: 31-10-2012, 11:41:30 »
Když ti to přijde jednodušší než:
Kód: Text [Vybrat]
  1. INSERT INTO tabulka(field1, field2, field3) VALUES ('a','b','c') RETURNING field_klic
tak proti gustu...

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 7430
  • Karma: 44
    • Verze Delphi: W11 + D11.3.1
Re:Získanie práve vytvoreného ID
« Odpověď #13 kdy: 31-10-2012, 12:10:24 »
Predpokladám, že by som to musel dať ako SP na stranu servera. Pre mňa je to jednoduchšie ako to mám(?).
1. bod musím robiť tak či tak.
2. a 3. bod robím len jediný raz.
4. bod musím robiť samostane pre každý prípad čo je jednoduché - malá pravdepodobnosť chyby

Používam TIBDataSet, kde sa mi všetky texty SQL generujú samé a už sa nestarám o "Insert.." na strane servera. Preto sa mi to zdá jednoduchšie riešenie.
Win11 64b, Delphi 12.2, FireBird 4.01
Expert na kladenie nejasne formulovaných otázok.

Offline Petr P.

  • Nováček
  • *
  • Příspěvků: 29
  • Karma: 1
    • Verze Delphi: Turbo Delphi 2006
Re:Získanie práve vytvoreného ID
« Odpověď #14 kdy: 31-10-2012, 14:50:46 »
Místo  SP můžeš použít  dotaz v IBQuery:
select gen_id(COUNTRY_GEN,1) from RDB$DATABASE
...
 ID:= IBQuery.Fields[0].AsInteger
« Poslední změna: 31-10-2012, 14:56:22 od Petr P. »