Tratando erros de banco de dados

Além de tratarmos os erros que podem acontecer em nossos sistemas, como dados informados incorretamente (máscara), data inválida, campo deve ter valor, etc, precisamos ainda tratar os erros que podem acontecer no Sistema Gerenciador de Banco de Dados (SGDB). Os erros mais comuns no banco de dados são de chave primária duplicada e chaves estrangeiras faltando.

Como o objetivo desse artigo é facilitar o máximo, iremos utilizar um formulário padrão do Delphi, chamado de ReconcileError. Esse formulário padrão é utilizado para tratar todas as exceções que acontecem no banco de dados, possibilitando que nossa aplicação interfira no processo. Inclusive possibilita que o usuário altere os dados, ou simplesmente desista da alteração ou inserção.

Para utilizar o ReconcileError, acesse o menu File > New > Other e escolha a aba Dialogs. Selecione Reconcile Error Dialog. Agora é necessário chamar o formulário. Para tanto, no evento OnReconcileError de todos os ClientDataSet coloque o código exibido abaixo:

Action := HandleReconcileError(DataSet, UpdateKind, E);

* Você pode colocar o código em somente um ClientDataSet e nos outras fazer a ligação do evento, assim centralizando esse código em um único local e diminuíndo o trabalho.

Adicione a Unit do ReconcileError no DataModule. Isso pode ser feito através do menu File > Use unit.

Quando o ReconcileError é chamado apresentará os dados que foram informados na aplicação, inclusive oferecendo a opção de visualizar somente os campos que sofreram alteração. Além disso, nos possibilita três ações para tratar a exceção (Reconcile Action):

· Skip : Simplesmente “escapa” sem tratar o evento, voltando para o formulário que o usuário estava;

· Cancel : Cancela a inserção ou alteração do registro;

· Correct : A mais interessante de todas, pois ao selecioná-la é possibilitado ao usuário a alteração dos dados no próprio formulário.

Além dessas três ações mais comuns, temos outras ações para tratar conflitos de registros que foram alterados ao mesmo tempo por mais usuários:

· Abort : Aborta o tratamento voltando para o formulário que o usuário estava.

· Merge : Possibilita a verificação dos dados que foram alterados por outros usuários e a junção com os dados alterados na sua aplicação.

* Depois que for exibido o ReconcileError e o usuário tomar uma das possíveis decisões ainda será necessário dar um comando ApplyUpdates para efetivamente gravar as alterações no banco de dados

Agora, para você utilizar o ReconcileError em suas aplicações falta somente fazer algumas traduções para que fique mais entendível para o usuário. Todos os componentes visíveis podem ser facilmente traduzidos. O trabalho mais pesado fica na hora de fazer algumas traduções nos código. Comece alterando as constantes conforme mostra o código abaixo:

const

ActionStr: array[TReconcileAction] of string = ('Escapar', 'Abortar', 'Merge', 'Corrigir', 'Cancelar', 'Atualizar');

UpdateKindStr: array[TUpdateKind] of string = ('Alteração', 'Inserção', 'Exclusão'); SCaption = 'Erro - %s';

SUnchanged = '<não alterado>';

SBinary = '(Binary)';

SAdt = '(ADT)';

SArray = '(Array)';

SFieldName = 'Nome do Campo';

SOriginal = 'Valor Original';

SConflict = 'Valor conflitante';

SValue = ' Valor';

SNoData = '<sem registro>';

SNew = 'Novo';

Outra possibilidade interessante é alterar o evento FormCreate do ReconcileError colocando alguns testes para verificar o tipo de erro que ocorreu e acrescentar uma tradução ao erro. Veja como deve ficar o código desse evento abaixo:

if FDataSet = nil then Exit;

FDataFields := TList.Create;

InitDataFields;

Caption := Format(SCaption, [FDataSet.Name]);

UpdateType.Caption := UpdateKindStr[FUpdateKind];

ErrorMsg.Text := FError.Message;

if FError.Context <> '' then

ErrorMsg.Lines.Add(FError.Context);

if Pos('PRIMARY',ErrorMsg.Text) > 0 then

ErrorMsg.Lines.Add('Tradução: Erro de Chave Primária!');

if Pos('FOREIGN',ErrorMsg.Text) > 0 then

ErrorMsg.Lines.Add('Tradução: Erro de Chave Estrangeira!');

if Pos('*** null ***',ErrorMsg.Text) > 0 then

ErrorMsg.Lines.Add('Tradução: Campo obrigatório não foi informado!');

ConflictsOnly.Enabled := FCurColIdx > 0;

ConflictsOnly.Checked := ConflictsOnly.Enabled;

ChangedOnly.Enabled := FNewColIdx > 0;

InitReconcileActions;

UpdateData.DefaultRowHeight := UpdateData.Canvas.TextHeight('SWgjp') + 7; { Do not localize }

Depois dessas alterações teremos todos os erros de validação devidamente tratados, através de uma apresentação ao usuário, que poderá decidir o que fazer.

Veja na Figura abaixo o ReconcileError com as traduções.