[ dogriz @ 29.11.2007. 09:02 ] @
U Firebird bazi su kreirane neke procedure, triggeri i exceptionsi...

Kako je moguće "uhvatiti" te exceptionse u Delphi aplikaciji koja koristi tu bazu? (DBExpress i ClientDataSet)

Znači, npr. prilikom upisa podataka u bazu iz delphi aplikacije, DB server odrađuje još neke dodatne stvari (koristeći procedure i triggere). Tu je moguće da se javi exception, koji ja ne znam da povežem sa aplikacijom
Neka prost primer bude employee.fdb baza koja ima već kreirane neke procedure i izuzetke, a delphi aplikacija koristi DBExpress i ClientDataSet za konekciju sa bazom.
[ savkic @ 29.11.2007. 11:50 ] @
> Znači, npr. prilikom upisa podataka u bazu iz delphi aplikacije, DB server odrađuje još neke dodatne stvari (koristeći procedure i triggere). Tu je
> moguće da se javi exception, koji ja ne znam da povežem sa aplikacijom

Exceptioni se handluju na standardni način, preko try exception ili try finally blokova. Npr. ako radiš insert i recimo narušava se primarni ključ, sa FB će javiti grešku koju će komponente pretvoriti u standarni Delphi Exception. Isto važi i za custom exceptione koje ti sam podižeš u bazi. Kod npr. može ovako izgledati:
Code:

try
  ds.Sql := 'INSERT INTO TABELA ....';
  ds.ExecSQL;
except
  on E: Exception do
   ShowMessage(e.Message);
end;
[ MatezYU @ 29.11.2007. 12:54 ] @
Mislim da razumem šta želiš. Imaš na Interbase paleti komponentu IBEvents. Ona može da ti uhvati događaj u bazi. Firebird ili Interbase RDBMS može u svojim trigerima da generiše neki događaj a aplikacija koja ima na sebi IBEvents komponentu može da reaguje ako uhvati ovaj događaj. Tako recimo možeš da uradiš npr. refresh nekog grida ako neki drugi korisnik recimo unese neki podatak a da se automatski posle inserta novog rekorda recimo opali triger koji aktivira ovaj event i on u svim aplikacijama koje su pokrenute uradi refresh. Mislim da je kombinacija delphi i firebird baze jako dobra pošto one tesno sarađuju u nekim segmentima. Sa drugim bazama ne možeš postići tako dobre rezultate.
[ dogriz @ 30.11.2007. 07:31 ] @
Evo jedan konkretan slikovit primer:
(baza je employee.fdb)

Procedura koja se izvrsava ADD_EMP_PROJ:
Code:

BEGIN
    BEGIN
    INSERT INTO employee_project (emp_no, proj_id) VALUES (:emp_no, :proj_id);
    WHEN SQLCODE -530 DO
        EXCEPTION unknown_emp_id;
    END
    SUSPEND;
END


Izuzetak unknown_emp_id:
Code:

CREATE EXCEPTION UNKNOWN_EMP_ID 'Invalid employee number or project id.';


Delphi kod kojim izvršavam gore navedenu proceduru:
Code:

procedure TForm1.btnExecuteClick(Sender: TObject);
begin
  try
    //SQLDataSet2 - Stored Procedure ADD_EMP_PROJ
    SQLDataSet2.Params.ParamByName('EMP_NO').AsInteger := -1; //namerno unet nepostojeci EMP_NO, da bi se izazvao izuzetak
    SQLDataSet2.Params.ParamByName('PROJ_ID').AsString := 'ABCDE';
    SQLDataSet2.ExecSQL();
  except
    on E: Exception do
      MessageDlg(E.Message, mtError, [mbOK], 0);
  end;
end;


Delphi daje sledeću poruku:
Citat:

Database Server Error: exception 1 UNKNOWN_EMP_ID
Invalid employee number or project id.
At procedure 'ADD_EMP_PROJ'


Da li je moguće izvući samo Exception Text, tj. "Invalid employee number or project id.", a ne kompletan E.Message?




Druga situacija je slična kao u prethodnom primeru, ali ovaj put se koristi ClientDataSet i unos preko DBGrid-a:

Code:

procedure TForm1.btnApplyUpdatesClick(Sender: TObject);
begin
  try
    ClientDataSet1.ApplyUpdates(0);
  except
    on E: Exception do
      MessageDlg(E.Message, mtError, [mbOK], 0);
  end;
end;


Kako u ovom slučaju doći do teksta izuzetka iz prethodnog primera?

PS. Klik na btnApplyUpdates ne vraća nikakvu poruku, ali naravno loši podaci neće biti zapisani u bazu.


@MatezYU: Predlog za IBEvents mi se sviđa, moraću i to da probam, pogotovo što nudi mnogo više od ovoga što sam hteo.
[ dogriz @ 30.11.2007. 09:39 ] @
Citat:
MatezYU: Mislim da razumem šta želiš. Imaš na Interbase paleti komponentu IBEvents. Ona može da ti uhvati događaj u bazi. Firebird ili Interbase RDBMS može u svojim trigerima da generiše neki događaj a aplikacija koja ima na sebi IBEvents komponentu može da reaguje ako uhvati ovaj događaj. Tako recimo možeš da uradiš npr. refresh nekog grida ako neki drugi korisnik recimo unese neki podatak a da se automatski posle inserta novog rekorda recimo opali triger koji aktivira ovaj event i on u svim aplikacijama koje su pokrenute uradi refresh. Mislim da je kombinacija delphi i firebird baze jako dobra pošto one tesno sarađuju u nekim segmentima. Sa drugim bazama ne možeš postići tako dobre rezultate.


Hm... Pokušao sam sa IBEvents-om, ali...
1. da bi mogao da funkcioniše, neophodan je GDS32.DLL, a ja sam sa Firebird-om koristim FBCLIENT.DLL. (znam da je dovoljno samo da se preimenuje DLL, ali sve sam konfigurisao za Firebird i FBCLIENT...)
2. veći problem je što ja radim sa DBExpress-om, tako da za IBEvents nije moguće postaviti "Database" property (morao bih koristiti IBDatabase, a ne TSQLConnection)

Dalje nisam ni probao, jer mi ovo gore navedeno dosta menja način rada, a za to baš nemam vremena, jer u duhu vremena radim RAD

U svakom slučaju, hvala na savetu. Možda i to jednog dana dođe na dnevni red
[ savkic @ 30.11.2007. 10:41 ] @
> Hm... Pokušao sam sa IBEvents-om, ali...
> 1. da bi mogao da funkcioniše, neophodan je GDS32.DLL, a ja sam sa Firebird-om koristim FBCLIENT.DLL. (znam da je dovoljno samo da se
> preimenuje DLL, ali sve sam konfigurisao za Firebird i FBCLIENT...)

Možeš imati i fbclient i gds32 paralelno, koliko znam u poslednjim verzijama IBX je moguće odabrati klijent biblioteku sa kojom će raditi. Svejedno, za to što tebi treba eventse je nemoguće upotrebiti. Eventi su posebni FB mehanizmi i koriste se u druge svrhe, imaš u dokumentaciji više detalja.

> 2. veći problem je što ja radim sa DBExpress-om, tako da za IBEvents nije moguće postaviti "Database" property (morao bih koristiti
> IBDatabase, a ne TSQLConnection)

Možeš ih paraleno koristiti, nije najsrećnije rešenje ali...

> Database Server Error: exception 1 UNKNOWN_EMP_ID
> Invalid employee number or project id.
> At procedure 'ADD_EMP_PROJ'

> Da li je moguće izvući samo Exception Text, tj. "Invalid employee number or project id.", a ne kompletan E.Message?

Kog tipa je exception? Obično konkretne db exception klase imaju i error code numeričkog tipa koji vraća integer vrednost greške. Te vrednosti su jedinstvene za pojedine greške tako da umesto teksta greške možeš ispitivati errorcode i na osnovu njega sam izdati poruku ili već šta je potrebno. Druga varijanta je da parsiraš tekst poruke i da izdvojiš željeni tekst.
[ dogriz @ 30.11.2007. 11:55 ] @
Citat:
savkic:
Kog tipa je exception? Obično konkretne db exception klase imaju i error code numeričkog tipa koji vraća integer vrednost greške. Te vrednosti su jedinstvene za pojedine greške tako da umesto teksta greške možeš ispitivati errorcode i na osnovu njega sam izdati poruku ili već šta je potrebno. Druga varijanta je da parsiraš tekst poruke i da izdvojiš željeni tekst.


Da, ja u Firebirdu definišem izuzetke i svaki ima svoj "Exception ID", "Exception Name" i "Exception Text". Samo nikako da ukapiram kako mogu da to sve koristim kako hoću iz Delphija. Mislio sam da postoji neko jednostavno rešenje, jer nikako ne želim da mi aplikacija obrađuje poruke o greškama, već database server.
Kako stvari stoje, izgleda ću za sada još uvek ostati na E.Message...
[ savkic @ 30.11.2007. 12:51 ] @
> Mislio sam da postoji neko jednostavno rešenje, jer nikako ne želim da mi aplikacija obrađuje poruke o greškama, već database server.

Sasvim je prirodno da greške obrađuje onaj od koga dolaze podaci, ne razumem kako bi to mogao činiti FB, razjasni malo.
[ dogriz @ 30.11.2007. 13:04 ] @
Citat:
savkic:Sasvim je prirodno da greške obrađuje onaj od koga dolaze podaci, ne razumem kako bi to mogao činiti FB, razjasni malo.


U Delphiju napišem INSERT INTO TABELA VALUES (:VAL1, :VAL2, :VAL3...) i prosledim tim parametrima bilo šta iz npr. EditBox-ova, a Firebird server proverava da li su VAL podaci validni - da li odgovaraju pripadajućem domenu, da li već postoji u bazi taj unique podatak, da li se prihvata NULL ili nešto mora biti uneto, da li postoji Master/Detail key... To je sve posao database servera, u ovom slučaju Firebirda, a nikako Delphi-ja.
Može i pre izvršavanja upita da se radi neka kontrola naravno (npr. provera ispravnosti datuma, da li je broj ceo, pozitivan, da li je uopšte broj itd.) u samoj Delphi aplikaciji, ali to nije dovoljno.
A i što ne bi isprojektovao dovoljno robusnu bazu koja je otporna na greške i gluposti operatera ili programera koji joj šalju podatke?
[ savkic @ 30.11.2007. 13:44 ] @
> su VAL podaci validni - da li odgovaraju pripadajućem domenu, da li već postoji u bazi taj unique podatak, da li se prihvata NULL ili nešto mora
> biti uneto, da li postoji Master/Detail key... To je sve posao database servera, u ovom slučaju Firebirda, a nikako Delphi-ja.

Obrada poruka o greškama (o čemu si ti prvo pisao) i provera fizičke i logičke konzistentnosti podataka su različite stvari, prvu uglavnom treba raditi na klijentu a drugu radi RDBMS.

> A i što ne bi isprojektovao dovoljno robusnu bazu koja je otporna na greške i gluposti operatera ili programera koji joj šalju podatke?

To je nemoguće u opštem slučaju.
[ dogriz @ 30.11.2007. 14:28 ] @
U principu meni je od sve obrade poruka o greškama, potrebno samo da se korisniku na ekranu prikaže ono što mu šalje DB (doduše, ono što sam hteo je da se te poruke pojave u malo drugačijem obliku, ništa više).

I, da ne zalazimo u dublju raspravu i ne udaljavamo se od prvobitne teme, da kažem još sledeće: ono što ja hoću da postignem sa "dovoljno robusnom bazom" je izvodljivo i moguće napraviti tako - da ne može da se ugrozi konzistentnost podataka u bazi - znači u prvom planu je baza, tj. podaci, a klijenti, korisnički interfejs i ostalo su irelevantni.