Autor Téma: Posledné slovo k výnimkám - snáď  (Přečteno 794 krát)

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5850
  • Karma: 42
    • Verze Delphi: W10 + Delphi 10.4 professional
Posledné slovo k výnimkám - snáď
« kdy: 03-07-2021, 08:49:57 »

Zaujíma ma len, či uvažovaná metodika/logika riešenia je správna.
.
Riešenie výnimiek má byť mimo obchodnej logiky. Prepokladám:
  • Triedu pre vlastné výnimky (EMyError). S vlastnými ErrorCode.
  • Triedu pre texty oznamy (VerboseError) pre BFU
Mám dve jednotky, kde sa pristupuje k DB:
FDFunction s TFDFunction: FDQuery.Open alebo FDQuery.Refresh, FDQuery.ExecSQL, FDQuery.Execute()
DBCustom s TCustomDB: FDTable.Post
Tieto akcie sa v kóde nikde inde nevyskytujú.
.
Príklad kódu v obchodnej logike:
Kód: Delphi [Vybrat]
  1. MyObject.DataOK;
  2. begin
  3.   if not inherited then  //  neobsahuje blok try - except
  4.     Exit;
  5.  
  6.  
  7.   try
  8.     TFDFunction.OpenQry(Myquery1);
  9.     FDBCustom.PostRecord;
  10.     TFDFunction.QryExec(Myquery2);
  11.   except
  12.     on E: Exception do
  13.       raise E.RaiseOuterException(MyException.Create(ErrorCode, E.Message))  // 1) raise asi nie je nutné
  14.     else
  15.       raise;
  16.   end;
  17. end;
V prípade potreby si do bloku try - except obalím jednotlivé dotkunuté funkcie, či časti kódu. Dôvod vidím v podhodení ErrorCode.
V triedach TFDFunction a TCustomDB uvažujem toto:
Kód: Delphi [Vybrat]
  1. begin
  2.   try
  3.     Query.ExecSQL
  4.   except
  5. //  2) Toto je asi zbytočné
  6. //    on E: EFDDBEngineException do
  7. //    begin
  8. //      Query.Transaction.Rollback;
  9. //      raise;
  10. //    end;
  11. //    on E: EDatabaseError do
  12. //    begin
  13. //      Query.Transaction.Rollback;
  14. //      raise;
  15. //    end;
  16. //  3) Tu si nie som istý, či to musí byť
  17.     on E: Exception do
  18.     begin
  19.       Query.Transaction.Rollback;
  20.       raise;  //  4) Nesie so sebou aj druh výnimky -  EFDDBEngineException, EDatabaseError...
  21.     end;
  22.   else
  23.     begin
  24.       Query.Transaction.Rollback;
  25.       raise;
  26.     end
  27.   end;
  28. end;
5) Podľa mojich vedomostí nemusím v on .. do vytvárať výnimku (E.Create...). O to sa postará raise.
v EMyError predpokladám rozpitvanie výnimky + podľa situácie
  • odoslanie výnimky na email
  • logovanie výnimky
  • využite Eurekalog - ešte o ňom nič neviem. Ale keď ho vlastním :)
Vychádzam zo svojho skalopevného presvedčenia, že nemám chybu v kóde. O toto som sa postaral:
  • Pripojenie k DB je aktívne
  • Transakcia je aktívna
  • TFDTable a TFDQuery sú vytvorené
  • SQL texty sú platné
Samozrejme nemôžem predísť situácii, že padne spojenie s DB, či zlyhá niečo iné.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline vandrovnik

  • Guru
  • *****
  • Příspěvků: 1237
  • Karma: 51
    • Verze Delphi: 10.3
Re:Posledné slovo k výnimkám - snáď
« Odpověď #1 kdy: 03-07-2021, 17:21:08 »
Ta druhá část se ale myslím dá napsat jednodušeji takto:

Kód: Delphi [Vybrat]
  1.     begin
  2.       // tady by se zahájila transakce
  3.       try
  4.         Query.ExecSQL;
  5.         // tady by to nejspíš chtělo commit
  6.       except
  7.         Query.Transaction.Rollback;
  8.         raise;  
  9.       end;
  10.     end;

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5850
  • Karma: 42
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Posledné slovo k výnimkám - snáď
« Odpověď #2 kdy: 03-07-2021, 23:12:15 »
Ta druhá část se ale myslím dá napsat jednodušeji takto:

Kód: Delphi [Vybrat]
  1.     begin
  2.       // tady by se zahájila transakce
  3.       try
  4.         Query.ExecSQL;
  5.         // tady by to nejspíš chtělo commit
  6.       except
  7.         Query.Transaction.Rollback;
  8.         raise;  
  9.       end;
  10.     end;
Ďakujem. Tým som si nebol istý. Transakciu mám obslúženú. Tak isto aj commit. Mám dve funkcie.

  • QryExecute(const Query: TFDQuery; const SQLType: TExecuteSQLType); static;
  • QryExecuteNoCommit(const Query: TFDQuery; const SQLType: TExecuteSQLType; const Transaction: TFDCustomTransaction);
V 1. je commit. 2. používam v prípade, keď v jednej dávke používam viac Query. Vtedy mám commit obslúžený v mieste konania.
Rád by som vedel, či v 1) je nutné použiť raise.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline vandrovnik

  • Guru
  • *****
  • Příspěvků: 1237
  • Karma: 51
    • Verze Delphi: 10.3
Re:Posledné slovo k výnimkám - snáď
« Odpověď #3 kdy: 03-07-2021, 23:42:30 »
Rád by som vedel, či v 1) je nutné použiť raise.

Když v prvním případě raise nepoužiješ, tak se volající nedozví, že došlo k problému - z jeho pohledu to bude vypadat úplně stejně, jako kdyby žádná výjimka nenastala.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5850
  • Karma: 42
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Posledné slovo k výnimkám - snáď
« Odpověď #4 kdy: 04-07-2021, 09:30:40 »
To som rád, že moja predstava bola potvrdená. Ďakujem. A idem na tie výnimky.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5850
  • Karma: 42
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Posledné slovo k výnimkám - snáď
« Odpověď #5 kdy: 04-07-2021, 12:39:47 »

Kód: Delphi [Vybrat]
  1.   EjstException = class(Exception)
  2.     constructor Create(const AErrorCode: DWord);
  3. const
  4.   jstErr_Mask = $80000000;
  5.   jstErr_DB_Group = $1000000;
  6.   EDB_Table_Post = jstErr_Mask or jstErr_DB_Group or $0001;
  7.     //  Použitie
  8.     on E:Exception do
  9.       raise E.RaiseOuterException(EjstException.Create(EDB_Table_Post));
Citace
[cc32 Error] DBCustom.pas(365): E2021 Class type required
Nerozumiem/netuším o čo ide pri tomto ozname. Prosím o vysvetlenie
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5850
  • Karma: 42
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Posledné slovo k výnimkám - snáď
« Odpověď #6 kdy: 04-07-2021, 16:43:41 »
Ak vynechám raise E.RaiseOuterException, tak to zbehne. Aha, viď
https://stackoverflow.com/questions/64834857/exception-raiseouterexception-vs-w1035-return-value-of-function-s-might-be-u
Snáď to nebude problém.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline Slappy

  • Plnoletý
  • ***
  • Příspěvků: 245
  • Karma: 12
  • Slappy
    • Verze Delphi: 10.2 Tokyo + Vsetky :)
    • unSigned
Re:Posledné slovo k výnimkám - snáď
« Odpověď #7 kdy: 04-07-2021, 17:10:11 »
Trochu OT:

Stano, riesi tvoj softver evidenciu vody, elektriny, poplatkov do fondu atd. v spolocenstvach vlastnikov bytov?
Moje projekty: http://www.unsigned.sk Tvorba cool dizajnovych instalatorov v NSIS a Inno Setup. Rozsirenie pre Visual Studio a RAD Studio pre tvorbu NSIS a Inno Setup instalatorov.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5850
  • Karma: 42
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Posledné slovo k výnimkám - snáď
« Odpověď #8 kdy: 04-07-2021, 18:41:11 »
Áno.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5850
  • Karma: 42
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Posledné slovo k výnimkám - snáď
« Odpověď #9 kdy: 12-07-2021, 17:05:03 »

Došiel som k tomuto výsledku. Je správny?
Kód: Delphi [Vybrat]
  1. //  Predpoklad: je to prvá výnimka (úroveň 0), ktorá môže nastať.
  2. function TCustomDB.CompositeUniqueIndexOK: Boolean;
  3. ...
  4.   except
  5.     on E: Exception do
  6.       raise E.Create('CompositeUniqueIndex');
  7.   end;
  8. .
  9. procedure TCustomDB.PostRecord(AAutoCommit: Boolean);
  10. ...
  11.      if not CompositeUniqueIndexOK then
  12.       Exit;
  13.   except
  14.     Exception.RaiseOuterException(Exception.Create('PostRecord'));   //  1*
  15.   end;
1* - takýmto spôsobom pokračovať pri ďalších úrovniach. Až po konenčné vybavenie výnimky.
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1556
  • Karma: 37
    • Pepak.net
Re:Posledné slovo k výnimkám - snáď
« Odpověď #10 kdy: 12-07-2021, 19:30:35 »
Ne.

Řádek 6 by za určitých okolností správný být mohl, ale protože sis jako obvykle nechal pro sebe, co se snažíš dosáhnout, tak se to nedá určit. Přinejmenším ale ztrácíš informaci o tom, k jaké chybě došlo, a nahrazuješ ji poměrně nepopisnou informací, že k chybě došlo někde v CompositeUniqueIndex. Já bych nejspíš celý try-except blok vyhodil úpolně.

Řádek 14 má stejnou chybu, plus dělá mě naprosto nesrozumitelnou složeninu normální a Outer výjimky. Jaký máš k něčemu takoému důvod? Proč prostě nenecháš výjimku, tu původní, probublat až k místu, kde ji chceš ošetřit? Pokud tě zajímá "cesta" k té výjimce, tak to se řeší nástroji jako EurekaLog nebo MadExcept, které si k výjimce uloží stack trace a dovolí ti, aby ses k němu dostal, pokud bys ho chtěl.

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5850
  • Karma: 42
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Posledné slovo k výnimkám - snáď
« Odpověď #11 kdy: 12-07-2021, 20:34:15 »

Citace
Proč prostě nenecháš výjimku, tu původní, probublat až k místu, kde ji chceš ošetřit?
Ak použijem len raise, tak sa výnimka zničí.Moja úvaha je, že dostanem rýchlu informáciu kde sa to pokazilo a odkiaľ to bolo volané. Takto to nechám prebublať cez všetky úrovne. Ak chyba bude v mojom kóde, tak mi to veľmi pomôže. V mojom prípade je 99 % výnimiek spojených s DB.
.
EurekaLog mám a hodlám ho v budúcnosti použiť. Ale to snáď na ťažšie prípady. A ešte ho musím naštudovať.
« Poslední změna: 12-07-2021, 20:35:57 od Stanislav Hruška »
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1556
  • Karma: 37
    • Pepak.net
Re:Posledné slovo k výnimkám - snáď
« Odpověď #12 kdy: 12-07-2021, 20:49:57 »
Excellent
Rated 1 time
Citace
Proč prostě nenecháš výjimku, tu původní, probublat až k místu, kde ji chceš ošetřit?
Ak použijem len raise, tak sa výnimka zničí.
1) Není pravda. Od toho právě Raise bez dalšího je, aby to znovu "aktivovalo" výjimku poté, co jsi něco ošetřil.
2) Pokud je cílem jen v except udělat Raise, tak je celý except blok zbytečný a v programu vůbec nemusel být. Akorát tím trocho (maličko) zdržuješ, jiný rozdíl v tom není.

Citace
Moja úvaha je, že dostanem rýchlu informáciu kde sa to pokazilo a odkiaľ to bolo volané. Takto to nechám prebublať cez všetky úrovne. Ak chyba bude v mojom kóde, tak mi to veľmi pomôže. V mojom prípade je 99 % výnimiek spojených s DB.
Použij třeba tu Eureku.

Citace
EurekaLog mám a hodlám ho v budúcnosti použiť. Ale to snáď na ťažšie prípady. A ešte ho musím naštudovať.
To mi připadá, jako kdyby ses tu půl roku pídil po tom, jak napsat formulář v čistém WinApi, protože TForm je pro tvé účely moc komplikovaný a musel by sis ho nastudovat. Neříkám, že nejsou situace, kdy tvůj přístup má opodstatnění (a někdy může být jediný smysluplný), ale ty neřešíš speciální situace - řešíš běžný případ a ve výsledku je tvoje řešení prakticky ve všech myslitelných ohledech horší. Fakt se na to vykašli a zkus si tu Eureku, když už ji máš koupenou. Nejspíš si vystačíš s tím, že to na projektu zapneš a ono to už ve výchozím nastavení bude vcelku uspokojivě fungovat - určitě lépe než to, co nám ukazuješ zatím.

(Btw., pořád mám dojem, že tvůj současný boj s výjimkami nemá racionální jádro. Že jsme tě přesvědčili, že chyby je dobré řešit výjimkami, takže ses do toho vrhl po hlavě s tím, že čím víc except bloků, tím lépe. Asi jako "čím víc proužků, tím víc Adidas". Zamyslel ses nad tím, proč vlastně ty výjimky chceš - co ti mají přinést? Chceš od nich něco víc než to, aby ses dozvěděl, ve kterém místě v programu k chybě došlo?)

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 5850
  • Karma: 42
    • Verze Delphi: W10 + Delphi 10.4 professional
Re:Posledné slovo k výnimkám - snáď
« Odpověď #13 kdy: 12-07-2021, 21:26:29 »
Citace
Chceš od nich něco víc než to, aby ses dozvěděl, ve kterém místě v programu k chybě došlo?
Momentálne nie. Nemám čo upratovať.
S tým raise, že neničí výnimku si ma dostal. Čo som si to vtrepal do hlavy! Ďakujem.
.
Ja len chcem, aby sa mi aplikácia nezrútila a v prípade neúspechu sa užívateľ o tom dozvedel. Toť všetko.
Viac krát som tu už písal: keby som si o tom s niekým 5 minút pohovoril, tak by som v tom mal jasno.
« Poslední změna: 12-07-2021, 21:28:35 od Stanislav Hruška »
W10 64b, Delphi 10.4, FireBird 3.05
Expert na kladenie nejasne formulovaných otázok.

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1556
  • Karma: 37
    • Pepak.net
Re:Posledné slovo k výnimkám - snáď
« Odpověď #14 kdy: 12-07-2021, 21:40:40 »
Ja len chcem, aby sa mi aplikácia nezrútila a v prípade neúspechu sa užívateľ o tom dozvedel. Toť všetko.
No ale pro tohle nepotřebuješ v běžné aplikaci dělat nic, protože přesně takhle se běžné aplikace chovají - bez ohledu na to, co je to za výjimku a kde k ní dojde, tak pokud ji někde neošetříš, tak postupně probublá až do "jádra Delphi", to ji předá do Application.OnException, kde ji ještě pořád můžeš vyřešit, a když to neuděláš, tak Delphi samy zobrazí chybovou hlášku o té výjimce a pak normálně nechají program pokračovat. Výsledný efekt je takový, že výjimka uživatele "vykopne" z tlačítka, které zrovna zmáčkl, ale to je tak zhruba všechno...