Обработка исключений при работе с базами данных
Одним из самых показательных примеров использования экземпляров исключений является известный пример работы с исключениями класса EDBEngineError при работе с базами данных. Особенно это касается баз данных Paradox и dBase, в которых не предусмотрено создание триггеров и ограничений. Последовательность действий следующая:
• Первоначально в секции Uses модуля подключаем блок BDE:
Uses.., BDE;
• В разделе Public объявления класса главной формы приложения объявляем процедуру обработки ошибок, например:
TForm1=Class(TForm)
… // Все иные необходимые объявления
Public
Procedure ShowErrMsg(NErr: Word); End;
• Создаем реализацию этой процедуры в разделе
Implementation модуля:
Procedure TForml.ShowErrMsg(NErr: Word);
Var SErr: String;
Begin
Case NErr Of
DBIERR KEYVIOL: SErr:=’Тайное значение ключа уже имеется!’; DBIERR_REQDERR: SErr:=’Для поля нужно указать значение!’;
Else
SErr:=’Ошибка при работе с данными ‘+IntToStr(NErr); End;
ShowMessage(SErr);
Raise EAbort.Create(»); End;
• В событии OnBeforeAction компонента DBNavigator включаем код:
If Button=nbPost Then // При сохранения данных в таблицах
Try
TableLPost; Except
On E: EDBEngineError Do Form1.ShowErrMsg(E.Errors[0].ErrorCode); End;
Для обработки ошибок, связанных с блокировкой таблицы другим пользователем можно использовать следующий обработчик.
Procedure TForm1.Table1EditError(DataSet: TDataSet; E: EDatabaseError;Var Action: TDataAction); Begin
ShowMessage(‘Ta6flnna недоступна для изменения данных!’); Action:=daAbort; End;
Четвертое событие используется при кэшировании изменений и имеет другой процедурный тип.
Назначение собственных обработчиков исключений
Вспомним, что когда на каком-либо уровне выполнения программы возникает исключительная ситуация и соответствующим образом не обрабатывается, объект Application выполняет метод HandleException, который проверяет содержимое поля FOnException (фактически проверяет наличие обработчика у события OnException). Таким образом, у программиста есть возможность перекрыть стандартную обработку исключения, определив метод-обработчик для события OnException. Формат этого метода должен соответствовать типу TExceptionEvent. В модуле Forms этот тип объявлен следующим образом:
Procedure(Sender: TObject; E: Exception) Of Object;
Другими словами, тип TExceptionEvent — это процедура, являющаяся объектом. Этот тип имеет поле FOnException, которое и хранит указатель на этот метод.
Известно два основных варианта подключения собственного обработчика события OnException:
— в файле-проекте приложения;
— в файле-главной форме приложения.
В первом случае файлы-формы приложения не загромождаются кодом, обрабатывающим исключения, однако требуется объявление класса, включающего процедуру-обработчик события типа TExceptionEvent. Во втором случае процедура-обработчик события обычно включается в состав класса-формы и делегируется объекту Application в событии OnCreate главной формы. Код в этом случае несколько проще.
а) Для того, чтобы назначить в файле-проекте приложения событию OnException собственный обработчик, надо в общем случае выполнить несколько действий:
• Создать новый проект. Все элементы обработки исключительных ситуаций можно разместить в Dpr-файле. Открыть Dpr-файл можно с помощью команды:
Project \ VeiwSource
• Создать пользовательский класс и его реализацию для создания собственного обработчика события.
• Подключить собственный обработчик события.
Program Project1; UsesSysUtils, Forms,
Unit1 In ‘Unitl.Pas’ {Forml}; Type
TMainExcHandler=CIass // Объявляем собственный класс
Public
Procedure ExcHandler(Sender: TObject; E: Exception); End;
Procedure TMainExcHandler.ExcHandler(Sender: TObject; E: Exception); Begin
<операторы обработки исключительной ситуации>% End;
Var MainExcHandler: TMainExcHandler; {$R *.RES} Begin
MainExcHandler:=TMainExcHandler.Create;// Создаем объект
II Подключаем обработчик
Application.OnException:=MainExcHandler.ExcHandIer; Application.Initialize; AppIication.CreateForm(TForml,Forml); Application.Run;
End.
Параметр Е — это экземпляр класса исключения Exception или одного из его потомков. С его помощью можно получить доступ к полям объекта обработки исключительных ситуаций, объявленных как Public или Published.
В качестве примера <операторов обработки исключительной ситуаций можно использовать выдачу в окне диалога строки-сообщения об ошибке:
MessageDlg(E.Message, mtError, [mbOK], 0);
Пример из подраздела по обработке ошибок в базах данных можно переделать следующим образом.
Procedure TMainExcHandler.ExcHandler(Sender: TObject; E: Exception); Var Serr: String; Begin
If E Is EDBEndineError Then Case E.Error[0].ErrorCode Of
DBIERR_KEYVIOL: Serr:=’TaKoe значение ключа уже имеется!’; DBIERR_REQDERR: Serr:=’Для поля нужно указать значение!’;
… II Другие ошибки, которые можно найти в файле BDE.INT
Else SЕгг:=’Ошибка при работе с данными ‘+IntToStr(NErr); End
Else SErr:=E.Message; ShowMessage(SErr); Raise EAbort.Create(»); End;
б) Для того, чтобы назначить в файле-главной форме приложения событию OnException собственный обработчик, надо в общем случае выполнить несколько действий:
• Объявить собственный обработчик события OnException:
TForml=Class(TForm)
… // Все иные необходимые объявления
Public
// Объявление собственного обработчика исключения
Procedure MyException(Sender: TObjcct; E: Exception); End;
• Создать реализацию объявленной процедуры:
Procedure TForm1.MyException(Sender: TObject; E: Exception);
Begin
If E Is EZeroDivide Then ShowMessage(E.Message)
Else ShowMessage(‘Другая ошибка!’) End;
• Подключить созданный обработчик к объекту Application:
Procedure TForm1.FormCreate(Sender: TObject);
Begin
AppIication.OnException:=MyException; End;
Если необходимость в собственном обработчике исключений отпала, то можно его отключить, переключив вывод сообщений обо всех ошибках на метод ShowException, например, следующим образом:
Application.OnException:=Nil;
Дополнительные функции для работы с исключениями
а) При работе с сокетами Windows могут возникать ошибки и возбуждаться исключения класса ESocketError, которые по умолчанию никак не обрабатываются. Delphi предоставляет пользователям возможность подключить свой обработчик, для чего предусмотрен соответствующий процедурный тип.
Туре
TSocketErrorProc=Procedure(ErrorCode: Integer);
Процедурный тип, которому должен соответствовать обработчик ошибок, возникающих при работе с сокетами Windows.
SetErrorProc(ErrorProc: TSocketErrorProc): TSocketErrorProc;
Заменяет программу реакции на исключение при возникновении ошибок в сокетах Windows.
б) Для преобразования кодов ошибок Win32 API можно использовать функцию:
SysErrorMessage(ErrorCode: Integer): String;
Возвращает строку сообщения об ошибке, соответствующую кодам ошибок Win32 API.
в ErrorAddr: Pointer;- Возвращает адрес оператора с ошибкой.
г) ExceptProc: Pointer — Переменная, указывающая на необработанные исключения. Можно использовать ее для уточнения данных об ошибке.
д) ErrorProc: Pointer — Переменная, указывающая на RTL обработчик ошибки во время выполнения программы. Оставлена для совместимости с Pascal.
е) В Delphi предусмотрена возможность регистрировать собственные исключения при организации взаимодействия по технологии CORBA, а когда исчезнет необходимость в исключении, то его можно исключить.
Для регистрации следует использовать следующие типы и функцию:
PExceptionDescription=Type Pointer; — Тип указателя, возвращаемый функцией регистрации пользовательского исключения.
PUserExceptionProxy=Type Pointer; — Тип результата пользовательского исключения.
TUserExceptionFactoryProc=Function: PUserExceptionProxy; cdecl; -Процедурный тип, которому должно соответствовать пользовательское исключение.
RegisterUserException(Name, RepositorylD: PChar;
Factory: TUserExceptionFactoryProc): PExceptionDescription; — Возвращает описание исключения, используя имя (Name) объявленного исключения.
Для каждого, определенного пользователем исключения в IDL файле сервера, необходимо определить потомка от исключения ECorbaUserExcep-tion. Затем для этого исключения следует создать функцию типа TUserExceptionFactoryProc и, наконец, следует зарегистрировать.
Для исключения следует использовать процедуру:
UnRegisterUserException(Description: PExceptionDescription); — Удаляет исключение, используя описание, возвращаемое функцией