Search code examples
delphidelphi-7

BDE vs ADO Database Error handling


I am working on Delphi 7 + SQLserver

in BDE all database related related erros can be handled using EDatabaseError

try

//all database related operations

Except

on EDatabaseError do
begin
  showmessage(e.message)  
end;

End;

but in ADO i tried different examples and i am getting different errors like EOleError/EDatabaseError/...

I Tried below 2 points to raise errors in ADO and i got different errors

1) In sql server stored procedure i am raising error on first line. when i execute that procedure using TADOStoredProc in delphi i am getting EOleError.

2) In TADOQuery i have written a wrong sql statement so when i open TADOQUery i am getting EDatabaseError.

so now i am confused how to handle ADO errors. i don't want to check for all the errors(EOleError,EDatabaseError,EAdoError...) in each and every form so i have written 2 examples, Please suggest me which one is good. if both are wrong please give me a good example.

Example 1:
Here i am showing only one form in example so Delphi Procedure HandleErrors and function GetErrorDescription may look stupid. i don't want to write same piece of code in all the forms. When it comes to real scenario i am gonna keep Delphi Procedure HandleErrors and function GetErrorDescription on different unit and use that unit all over the application.

type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    Procedure HandleErrors(e: Exception );
    function GetErrorDescription : WideString;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.GetErrorDescription : WideString;
var
  LastErrorIndex : Integer;
begin
  LastErrorIndex  :=ADOConnection1.Errors.Count-1;
  Result:=ADOConnection1.Errors.Item[LastErrorIndex].Description;
  //Code            :=ADOConnection1.Errors.Item[LastErrorIndex].NativeError;
end;

procedure TForm1.HandleErrors(e: Exception);
var
  Code: Integer;
  ErrorDescription: WideString ;
begin
  if e is EOleError then
    ShowMessage(GetErrorDescription)
  else
  if e is EDatabaseError then
    ShowMessage(GetErrorDescription)
  else
  if e is EADOError then
    ShowMessage(GetErrorDescription)
  else
    ShowMessage(GetErrorDescription)
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
   // any database related operations
  except
    on E : Exception do
    begin
      HandleErrors(E);
    end;
  end;
end;

end.

Example 2:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,ADODB, StdCtrls, DB,COMOBJ;

type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  LastErrorIndex : Integer;
begin
  try
   // any database related operations
  except
    on E : Exception do
    begin
      LastErrorIndex  :=ADOConnection1.Errors.Count-1;
      ShowMessage(ADOConnection1.Errors.Item[LastErrorIndex].Description);
    end;
  end;
end;

end.

which example is better. Can you please suggest a good one


Solution

  • As I said in a comment, you shouldn't scatter AdoConnections and datasets across multiple forms/ Instead you should put them in a datamodule then Use the datamodule's unit in your forms' units. That way, you will be able to connect TDataSources and db-aware components on the form to the datamodule's datasets.

    The other thing you can do is to install an application-wide exception handler to centralize your exception handling, if that's what you want to do. Delphi's Application object has an OnException event which you can assign to your own exception handler using code like that shown below.

    A downside of an application-wide exception handler is that it can be difficult in the OnException handler to identify which of your objects is actually responsible for causing the exception.

    type
      TMainForm = class(TForm)
        [...]
        procedure FormCreate(Sender: TObject);
      private
        procedure ApplicationException(Sender: TObject; E: Exception);
      public
      end;
    
    procedure TMainForm.FormCreate(Sender: TObject);
    begin
      Application.OnException := ApplicationException;
    end;
    
    procedure TMainForm.ApplicationException(Sender: TObject; E: Exception);
    var
      AErrors : Errors;
      AError : Error;
      i : Integer;
      S : String;
    begin
      Caption := 'Exception';
      if E is EDatabaseError then begin
        AErrors := DataModule1.AdoQuery1.Connection.Errors;
        for i := 0 to AErrors.Count - 1 do begin
          AError := AErrors.Item[i];
          S := Format('Number: %d, NativeError: %d, source: %s, description: %s',
            [AError.Number, AError.NativeError, AError.Source, AError.Description]);
          Memo1.Lines.Add(S);
        end;
      end;
    end;