Results 1 to 12 of 12

Thread: Event OnPostError wordt niet uitgevoerd.

  1. #1
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747

    Event OnPostError wordt niet uitgevoerd.

    Ik heb een tabel, waarin ik labels maak voor een vertaling. Om geen redundantie te krijgen heb ik in de database voor die tabel een index gemaakt, die uniek is. Twee keer het woord 'kleur' is nogal overdreven. Nu maak ik gebruik van dit event:
    Delphi Code:
    1. procedure TDMVertalingen.SQLVertaallabelsPostError(DataSet: TDataSet;
    2.   E: EDatabaseError; var DataAction: TDataAction);
    3. begin
    4.   showmessage(E.Message);
    5.   DataAction := daAbort;
    6. end;
    Als ik dan een woord invoer, die al bestaat, zal ik verwachten dat de OnPostError wordt uitgevoerd. Of heb ik dat helemaal fout? De framework (SQLdb) zal dit toch moeten afhandelen?
    Nu krijg ik continue de melding dat er inderdaad een fout is opgetreden in de database en of ik moet doorgaan of het programma moet afbreken. Ik vind het nogal wat voor een normale gebruiker.

    lazarus 1.62 / FPC 3.0 / Windows
    Delphi is great. Lazarus is more powerfull

  2. #2
    Krijg je die melding ook als je je programma buiten de IDE om start?

    Exceptions worden altijd gemeld aan de programmeur. Je kunt de exception negeren (en altijd negeren door het vinkje te zetten) waarna je eigen code alsnog uitgevoerd zou moeten worden.

    En buiten de IDE om zou je die melding dan niet moeten krijgen.

  3. #3
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    Ik heb een clean build uitgevoerd met de debugger uit. Programma los opgestart. Na het invoeren van hetzelfde woord komt dit tevoorschijn:
    Click image for larger version. 

Name:	posterror_trigger_fpc3.png 
Views:	128 
Size:	37.4 KB 
ID:	7471
    Na de foutmelding zou de insert ook gecanceld moeten worden. De OnPostError wordt niet getriggerd
    Delphi is great. Lazarus is more powerfull

  4. #4
    Heb je gecontroleerd of je daadwerkelijk in de OnPostError terecht komt ??

    In TDataset.Post wordt dit gedaan
    If Not TryDoing(@InternalPost,OnPostError) then exit;

    En daarin wordt toch echt de OnPostError aangeroepen in geval van een EDataBaseError.

    Edit: o wacht, je zegt al dat ie niet getriggerd wordt.
    Kun je eens een heel klein testprojectje maken waarin je test of de OnPostError goed werkt.

  5. #5
    Mmm. Je hebt wat betreft SQLdb.

    Het probleem is dat er nog geen communicatie met de server is bij Post.
    Dus je krijgt ook nooit die OnPostError.

    Het probleem komt pas naar voren bij een ApplyUpdates (of door sqoAutoApplyUpdates in Options op te nemen).
    De ApplyUpdates wordt altijd gedaan NA de Post en daar krijg je de exception dus terug.

    Nu is er ook een TSQLQuery.OnUpdateError die je kunt gebruiken.
    Daar zou je dan een nette melding kunnen geven.

    Ik heb heel die ApplyUpdates altijd een hele rare gevonden. Want ik kom af van Delphi/IBX en daar wordt bij een TIBQuery.Post al direct gecommuniceerd met de server.

    Je kunt natuurlijk ook dit doen:
    Delphi Code:
    1. SQL.Insert;
    2. SQL.FieldByName('ID').AsInteger := 1;
    3. try
    4.   SQL.Post;
    5.   SQL.ApplyUpdates;
    6. except
    7.   Showmessage('woops. dit kan natuurlijk ook');
    8. end;

    Maar ik heb hieronder even een complete unit gezet. Je kunt een nieuw project aanmaken met één button.
    Dubbelklik die button en doe een Select All en plak dit er totaal overheen.

    Deze laat dan ook zien dat het probleem in de ApplyUpdates zit. (de try/except rond de Post/ApplyUpdates heb ik even laten staan)

    Delphi Code:
    1. unit Unit1;
    2.  
    3. {$mode objfpc}{$H+}
    4.  
    5. interface
    6.  
    7. uses
    8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics,
    9.   Dialogs, StdCtrls, IBConnection, sqldb, DB, BufDataset;
    10.  
    11. type
    12.  
    13.   { TForm1 }
    14.  
    15.   TForm1 = class(TForm)
    16.     Button1: TButton;
    17.     procedure Button1Click(Sender: TObject);
    18.   private
    19.  
    20.   public
    21.  
    22.     procedure DoPostError(DataSet: TDataSet; E: EDatabaseError; var DataAction: TDataAction);
    23.     procedure DoApplyUpdateError(Sender: TObject; DataSet: TCustomBufDataset; E: EUpdateError;
    24.       UpdateKind: TUpdateKind; var Response: TResolverResponse);
    25.  
    26.   end;
    27.  
    28. var
    29.   Form1: TForm1;
    30.  
    31. implementation
    32.  
    33. {$R *.lfm}
    34.  
    35. { TForm1 }
    36.  
    37. procedure TForm1.DoPostError(DataSet: TDataSet; E: EDatabaseError; var DataAction: TDataAction);
    38. begin
    39.   ShowMessage('my error in Post');
    40.   DataAction := daAbort;
    41. end;
    42.  
    43. procedure TForm1.DoApplyUpdateError(Sender: TObject; DataSet: TCustomBufDataset; E: EUpdateError;
    44.   UpdateKind: TUpdateKind; var Response: TResolverResponse);
    45. begin
    46.   ShowMessage('my error in ApplyUpdate');
    47.   Response := rrAbort;
    48. end;
    49.  
    50. procedure TForm1.Button1Click(Sender: TObject);
    51. var
    52.   IB: TIBConnection;
    53.   SQL: TSQLQuery;
    54. begin
    55.   IB := TIBConnection.Create(nil);
    56.   SQL := TSQLQuery.Create(nil);
    57.   try
    58.     IB.Transaction := TSQLTransaction.Create(IB);
    59.     IB.Transaction.DataBase := IB;
    60.     IB.DatabaseName := 'c:\temp\test2.fbd';
    61.     IB.HostName := 'localhost';
    62.     IB.UserName := 'SYSDBA';
    63.     IB.Password := 'masterkey';
    64.     try
    65.       IB.Connected := True;
    66.     except
    67.       on E: EDatabaseError do
    68.       begin
    69.         IB.CreateDB;
    70.         IB.Connected := True;
    71.         IB.ExecuteDirect('CREATE TABLE NAME(ID BIGINT PRIMARY KEY);');
    72.         if TSQLTransaction(IB.Transaction).Active then
    73.           TSQLTransaction(IB.Transaction).Commit;
    74.       end;
    75.     end;
    76.  
    77.     SQL.OnPostError := @DoPostError;
    78.     SQL.OnUpdateError := @DoApplyUpdateError;
    79.     SQL.Database := IB;
    80.     SQL.Transaction := IB.Transaction;
    81.     SQL.SQL.Text := 'SELECT * FROM NAME';
    82.     SQL.Open;
    83.     SQL.Last;
    84.  
    85.     Button1.Caption := IntToStr(SQL.RecordCount);
    86.  
    87.     SQL.Insert;
    88.     SQL.FieldByName('ID').AsInteger := 1;
    89.     try
    90.       SQL.Post;
    91.       SQL.ApplyUpdates;
    92.     except
    93.       Showmessage('woops. dit kan natuurlijk ook');
    94.     end;
    95.  
    96.     SQL.Close;
    97.     if TSQLTransaction(SQL.Transaction).Active then
    98.       TSQLTransaction(SQL.Transaction).Commit;
    99.  
    100.   finally
    101.     IB.Free;
    102.     SQL.Free;
    103.   end;
    104.  
    105. end;
    106.  
    107. end.

  6. #6
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    Ik heb even snel iets in elkaar gezet in Delphi (mysql / MyDAC) en deze regel n de event toegevoegd.
    Delphi Code:
    1. procedure TForm1.MyQuery1PostError(DataSet: TDataSet; E: EDatabaseError;
    2.   var Action: TDataAction);
    3. begin
    4.   showmessage('fout in post');
    5.   action := daAbort;
    6. end;
    die geeft wel de showmessage weer. Alleen snap ik dan de action niet, want dan had ik verwacht dat deze de hele handeling in de dataset afbreekt en de ingevoerde regel verwijderd uit de grid / dataset.
    Dat gebeurt wel als ik naderhand ook dataset.cancel uitvoer.

    Maar lazarus triggert de hele onposterror niet.
    Delphi is great. Lazarus is more powerfull

  7. #7
    We posten allebei op hetzelfde tijdstip. Zie mijn vorige post.
    Het voorbeeld daarin is opzichzelf staand en maakt ook een firebird database aan in c:\temp

  8. #8
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    Oke. Testen met applyupdates event. Dan heeft die onposterror event in lazarus i.c.m. SQLdb geen nut.
    Delphi is great. Lazarus is more powerfull

  9. #9
    Quote Originally Posted by jkuiper View Post
    Oke. Testen met applyupdates event. Dan heeft die onposterror event in lazarus i.c.m. SQLdb geen nut.
    Het zou nog steeds kunnen zijn dat de onderliggende dataset/databaseconnectie besluit een exception te geven bij een Post zonder dat er nog echt data naar de server gegaan is. Ik weet ook niet of alle onderliggende tdatabaseconnection's gebruik maken van applyupdate om pas data naar de server te sturen.

  10. #10
    Hi John

    Ik gebruik in mySQL + myDAC onderstaand, waarbij ik eerst een aantal constante defineer :

    const
    {Declare constants we're interested in}
    ER_DUP_KEY = 1062;
    CR_CONN_HOST_ERROR = 2003;
    ER_ACCESS_DENIED_ERROR = 1045;


    Iedere table, bijv. in dit voorbeeld met namen van bank heb ik een unieke index op het veld 'Name'

    Dan de OnPostError gebruikt onderstaande code met als resultaat zie de bijlage:

    Code:
    procedure TdmBank.BankPostError(DataSet: TDataSet; E: EDatabaseError;
      var Action: TDataAction);
    begin
     if (E is EMyError) then begin
        if (EMyError(E).ErrorCode=ER_DUP_KEY) then begin
           Application.MessageBox(PCHAR('De naam '+ UpperCase(Bank.fieldByName('Name').AsString)+' bestaat al.'+#10+'Een naam of omschrijving mag maar één keer voorkomen!.'), 'Mededeling', MB_OK+MB_ICONEXCLAMATION+MB_DEFBUTTON1+MB_APPLMODAL);
           Bank.cancel;
           Abort;
        end;
      end;
    end;
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	foutmelding.jpg 
Views:	121 
Size:	62.4 KB 
ID:	7472  

  11. #11
    Quote Originally Posted by mierlp View Post
    Ik gebruik in mySQL + myDAC onderstaand, waarbij ik eerst een aantal constante defineer
    Ja... maar de clue hier is dat met TSQLQuery de Post niet communiceert met de server waardoor die OnPostError niet getriggered wordt.

    De TSQLQuery is inherited van TCustomBufDataset en die doet met Post eigenlijk niets (behalve een interne controle op verplichte velden). Pas bij de ApplyUpdates krijg je communicatie met de server dus de exception maar de OnPostError wordt dus niet uitgevoerd. Dat is dus het probleem/nadeel van TCustomBufDataset (en afgeleiden).

    Mijn vermoeden is dat de myDAC SQL-dataset WEL direct van TDataset inherited is. En TDataset heeft geen Applyupdates nodig (dat is alleen iets van een buffered TCustomBufDataset). Dus bij myDAC wordt de OnPostError wel direct getriggered omdat er direct communicatie met de server wordt gedaan bij .Post.

  12. #12
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    Dat klopt. Heb met dezelfde tool in Delphi getest. Maar vergeet niet, Peter, dat we hier te maken hebben met lazarus en een ander framework.
    Delphi is great. Lazarus is more powerfull

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •