Данная статья посвящена обработке ошибок и основана на официальной документации.
Введение
Класс EFDDBEngineException является базовым для всех ошибок DBMS. Экземпляр класса представляет собой коллекцию ошибок БД, доступных через свойство EFDDBEngineException.Errors[], а также представленных классом TFDDBError.
FireDAC подразумевает персонализацию и унификацию EFDDBEngineException исключений TFDDBError ошибок. “Персонализация” означает, что драйвер может иметь свои собственные исключения и классы ошибок, которые содержат информацию, специфичную для DBMS. Далее, в документации идет такая таблица
TFDDBError имеет свойство ErrorCode, которое содержит нативные коды ошибок DBMS
Унификация означает, что все классы исключения унаследованы от EFDDBEngineException – базового класса, который содержит независимую информацию о драйверах. Свойство этого класса Kind это независимая ошибка DBMS. В качестве примера, обработка ошибки уникальности ключа может быть следующей.
1 2 3 4 5 6 7 8 9 |
try FDQuery1.ExecSQL('insert into MyTab(code, name) values (:code, :name)', [100, 'Berlin']); except on E: EFDDBEngineException do begin if E.Kind = ekUKViolated then ShowMessage('Please enter unique value !'); raise; end; end; |
В справке указаны следующие TFDCommandExceptionKind
FireDAC.Stan.Error.TFDCommandExceptionKind
1 2 3 4 |
TFDCommandExceptionKind = (ekOther, ekNoDataFound, ekTooManyRows, ekRecordLocked, ekUKViolated, ekFKViolated, ekObjNotExists, ekUserPwdInvalid, ekUserPwdExpired, ekUserPwdWillExpire, ekCmdAborted, ekServerGone, ekServerOutput, ekArrExecMalfunc, ekInvalidParams); |
Информация об ошибках содержится в следующих свойствах класса EFDDBEngineException
- Errors — коллекция TFDDBError объектов.
- ErrorCount — Число ошибок коллекции.
- Kind — Независимые от DBMS ошибки.
- Message — актуальное сообщение ошибки.
А также в свойствах TFDDBError
- ErrorCode — Специфические ошибки DBMS.
- Kind — Общие для всех DBMS ошибки.
- Message — Сообщения об ошибках
Техника обработки ошибок
Собственно обработка ошибок может осуществляться несколькими способами
1) Традиционно try / except / end
1 2 3 4 5 6 7 8 9 10 11 |
FDConnection1.StartsTransaction; try FDQuery1.ExecSQL; FDConnection1.Commit; except on E: EFDDBEngineException do begin FDConnection1.Rollback; // do something here raise; end; end; |
2) Через обработку события TFDQuery.OnError
3) Через обработку события TFDConnection.OnError
Предыдущие 2 способа хороши для “логирования” исключений или настройки исключений, например
Пример из документации
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
procedure TForm1.FDConnection1Error(ASender: TObject; const AInitiator: IFDStanObject; var AException: Exception); var oExc: EFDDBEngineException; begin if AException is EFDDBEngineException then begin oExc := EFDDBEngineException(AException); if oExc.Kind = ekRecordLocked then oExc.Message := 'Please, try the operation later. At moment, the record is busy' else if (oExc.Kind = ekUKViolated) and SameText(oExc[0].ObjName, 'UniqueKey_Orders') then oExc.Message := 'Please, provide the unique order information. It seems, your order was already put'; end; end; FDConnection1.OnError := FDConnection1Error; |
4) Через обработку TFDQuery.OnExecuteError для специфических ошибок Array DML
5) Через обработку TFDQuery.OnUpdateError для обработки ошибок при инструкции Update
6) Через обработку событий TFDConnection.OnLost, OnRestored, OnRecover для обработки ошибок потери соединения.
GUI для конечного пользователя
Чтобы воспользоваться этой возможностью, нужно сделать следующее – добавить на форму TFDGUIxErrorDialog,
Диалог ловит событие TApplication.OnException и выдает всплывающее сообщение. Вкладка Query позволяет увидеть SQL команду, которая привела к ошибке. Ctrl+C копирует информацию об ошибке в буфер.