jul 072013
 

Buenas,

Cualquiera que haya realizado una aplicación con acceso a base de datos Firebird (o a una base de datos en general), habrá “lidiado” con los mensajes de error devueltos por el motor. Estos mensajes en inglés suelen ser bastante “feos” para mostrarlos tal cual al usuario, al cual no le aportan ningún tipo de información útil porque no suele entender lo que dice o cuál es el problema. En la entrada de hoy, y con la ayuda de una anterior, vamos a ver una forma de mostrar al usuario éstos mensajes de error dando algo más de información útil y que también podremos usar para crear algún tipo de log de errores.

Los componentes de acceso a Firebird usados en la demo son FireDAC dado que nos brindan de un acceso nativo al motor. No obstante, se ha hecho de tal manera que sea sencillo extrapolarlo a otros componentes (sobretodo si dan acceso nativo).

Si bien la demo se va a centrar en los errores producidos cuando se acepta un registro, la idea es extensible a los demás errores provocados por el motor. Así pues, al lío!

Una práctica usual para capturar dichos errores es usar un bloque try...except...end, soliendo mostrar el mensaje devuelto por el motor. Algo parecido a esto:

try
  DataSet.Post;
except
  on E: Exception do
    ShowMessage(E.Message);
end;

o bien poniendo un mensaje en español genérico del estilo “Error grabando registro”, o cosas por el estilo.

Lo primero que tenemos que averiguar es la clase del error que se genera, y eso lo conseguiremos con estas sencillas líneas de código:

try
  DataSet.Post;
except
  on E: Exception do
    ShowMessage(E.ClassName);
end;

Con esto vemos que la excepción generada es de tipo EIBNativeException. Esta clase, que deriva de EDatabaseError, tiene una propiedad ErrorCode que nos dará el código de excepción lanzado por el motor, y gracias al cual podremos personalizar los mensajes y actuar en consecuencia. Los valores de este código son del estilo 335544XXX aunque la mayoría de componentes de acceso nativo suelen definir una serie de constantes para cada uno de los posibles valores y, por suerte para nosotros, suelen ponerse de acuerdo en la nomenclatura de las mismas. En el caso de FireDAC es la unit uADPhysIBCli.

Estructura de clases

Estas serán las clases que usaremos para nuestro propósito y que pasaremos a explicar y desgranar a continuación.

UML post errors

La clase TFBErrors.

Esta clase será la clase base, la que nos hará el trabajo oscuro gracias a sus métodos protegidos (protected). Definiremos un constructor estándar capaz de aceptar cualquier tipo de excepción y conexión, para luego redefinirlo en las clases descendientes según los componentes de acceso escogidos.

Esta clase tiene 2 métodos abstractos (que tendremos que implementar en las clases descendientes), uno es GetErrorCode, que nos devolverá el código de error devuelto por el motor y CreateMeta, que creará el objeto TFBMetaData para acceder al metadato de la base de datos (el cual también depende de los componentes de acceso y por tanto es necesario crearlo en las clases especializadas).

Los demás métodos protegidos se encargarán de extraer la información necesaria de los mensajes de error devueltos por el motor y devolver un mensaje más “entendible” para el usuario o para generar nuestro log de errores. Siempre que sea posible, estos métodos devolverán, entre otros, nombre de la tabla, índice, campos que provocan en error y/o motivo del mismo.

 La clase TFBErrorsFireDAC

Esta será la clase especializada de TFBErrors para FireDAC.

Como podemos ver en el diagrama de clases, implementamos los métodos abstractos de la clase padre así como el método GetMessageError para terminar de adaptarlo a nuestras necesidades.

También podemos ver que “especializamos” nuestro constructor para que sólo pueda recibir componentes FireDAC.

Para facilitar el trabajo al programador, también hemos definido una función de clase, GetFBMessageError que básicamente creará un objeto TFBErrorsFireDAC y devolverá el resultado de la llamada al método GetMessageError.

 Uso de la clase

Pues ya sólo nos queda ver cómo usamos nuestra clase recién creada, y qué mejor que verlo en un ejemplo:

procedure TMainFrm.bPrimaryClick(Sender: TObject);
begin
  qMaster.Append;
  qMaster.FieldByName('id').AsInteger := 1;
  try
    qMaster.Post;
  except
    on E: Exception do
    begin
      ShowMessage(TFBErrorsFireDAC.GetFBMessageError(E, ADConnection1));
      qMaster.Cancel;
    end;
  end;
end;

Fijémonos en el control de la excepción, basta con poner en el uses la unidad donde estará definidas nuestras clases y hacer una llamada al método de clase con los parámetros necesario. Tan simple como esto 🙂

En el programa demo que adjunto podréis probar 7 de los posibles errores devueltos por Firebird, como:

  • Calve primaria duplicada
  • Deadlock (para éste tendréis que abrir 2 instancias de la demo)
  • Clave única duplicada
  • Campo requerido
  • Clave foranea
  • Validación de una columna (FireDAC no controla esta excepción, por lo que el tipo de error devuelto no es EIBNativeException sino EDatabaseError, por lo que no se puede gestionar correctamente)
  • Constraint check

Como siempre, podéis bajaros la unit con las clases, así como un programa demo para probarlo desde aquí.

Espero que os sea de utilidad.

Nos leemos

  2 Responses to “Personalizando los mensajes de error de Firebird”

  1. Excelente aporte, lo implementaré pronto. Gracia

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)