PDA

Ver la Versión Completa : Manejo De Errores En Bases De Datos


FelipeDiaz
13-12-2007, 23:24:46
Hola,

Sigo desarrollando una aplicacion de delphi que accesa un BD de FIREBIRD.

He avanzado gradualmente sobre algunos obstaculos.

En este momento me encuentro frente a dos situaciones de manejo de errores:

La primera:

Cuando el usuario intenta grabar un nuevo registro de la tabla CLIENTES, se pueden presentar tres posibles errores
1. Que intenta duplicar la Clave.
2. Que intenta Duplicar el Nombre del cliente.
3. Que intenta colocar un cupo de credito Negativo.

La primera es una restriccion de PRIMARY KEY, la segunda es una de indice UNICO, y la tercera es violacion a un CHECK.


Mi pregunta es..... como detecto que violacion me genero el error para mandarle al Usuario el mensaje apropiado:
"Intenta crear un Codigo ya existente" ó
"Nombre de cliente ya existente" ó
"VAlor debe ser mayor que cero"

Si no es posible, ayudenme con una alternativa para enfrentar la situacion.


--------------------------

y Segunda:

Por medio de un artificio, un dato que es flotante, ejemplo: "0,055", se muestra en un DBEdit como "5%", osea expresado en porcentajes, mediante las porpiedades del campo getText y SetText.

Cuando el usuario esta editando el DBGrid, existe la posibilidad que no borre el signo %, y este quede como una entrada.

(El DBEdit, impide que el usuario teclee el signo %, directamente, pero este no es el caso porque se ingreso por codigo, por als propiedades mencionadas)


El problema es que cuando el usuario hace POST, estando el signo %, se genera un Error, algo asi como.....EConvertError.

He tratado de buscar la forma de bloquearlo y mas bien obligar a que el usuario quite ese signo. Pero No se dodne ubicarlo, no se como capturarlo.


Espero haberme explicado bien.

Saludos.

Felipe Diaz.

Neftali [Germán.Estévez]
14-12-2007, 10:43:52
Mi pregunta es..... como detecto que violacion me genero el error para mandarle al Usuario el mensaje apropiado:

Lo lógico sería que utilizaras un Try..except. Cuando te salte las excepción, revisa si además del tipo tiene un code; Normalmente ese code es el que te distingue entre esos tres casos que has comentado.

FelipeDiaz
14-12-2007, 14:45:30
Hola neftali, yo hago uso del Try Except, solo que no se como obtener los codigos de los mensajes, porque el error no me los informa.

Neftali [Germán.Estévez]
14-12-2007, 17:01:02
Primero hay que saber de que tipo es la excepción.
Por ejemplom capturas la excepción con try..except y el tipo Exception y a partir de ahí muestras el ClassName de E.


try
error
except
on E:exception do begin
Mostrar E.ClassName
end;
end;


E.ClassName te mostrará de que tipo es la excepción. Por ejemplo si fuera con ADO sería un EOLEException.

Buscas en la ayuda EOLEException y varás que posee las propiedades E.Message y E.ErrorCode. LA que tú captures tal vez también lo tenga (No estoy familiarizado con las que devolverá FB).

Una vez que tengas la Clase y el Código (opcional) puedes usar un try..except más
específico:


try
error
except
on E:EOLEException do begin

if (E.ErrorCode =555) then begin
...
end
else if (E.ErrorCode =666) then begin
...
end
else begin
....
end;
end;
end;

Lepe
14-12-2007, 17:35:58
Los errores dependen de tus componentes de acceso, yo uso los mdo y capturo los errores así:

if (e is EMDOError) then
begin
strDebug := 'SqlCode: ' +inttostr(EMDOError(E).SQLCode) + espacio + E.ClassName;
strMessage:=EMDOError(E.Message);


Por el SQLCode, puedes saber qué tipo de error es. Existe un listado de esos números en www.firebird.com.mx

El mejor sitio para capturar el error, sería el OnPostError de tu dataset. En algunos casos, en el propio mensaje de error, dice que se viola la restricción "PK_CLIENTES_1", ese nombre lo verás en el Ib Expert, en las restricciones de esa tabla (Constraints, secondary indices, etc).

Además de lo anterior, en un ApplicationsEvents.OnException puedes añadir mensajes que ocurren para casos generales.

Dicho de otra forma, escribes código en el OnPostError para los mensajes de clave primaria. Si se viola una restricción UNIQUE, el código lo escribes en el ApplicationsEvents informando con un mensaje más general:"El valor introducido ya existe en la base de datos".

Saludos

FelipeDiaz
14-12-2007, 21:15:29
Hola neftali y Lepe.

Antes que todo muchas gracias de seguro que ambas funcionan.
El problema es que no domino el tema bien pero con la orientacion de ustedes uno se acerca y parende, me demore en dar con la forma apropiada para el codigo.

A la alternativa de Neftali es facil hacerle seguimiento, y comprenderla...la E.ClassName es...... "EFIBInterBaseError"

y con la instruccion.. Showmessage(inttostr(E.SQLCode));,

pude saber cual es el codigo.

PERO..... para la violacion de la clave Primaria y para la violacion de la unicidad del Nombre del cliente, me genera el mismo error. "-803"

En cambio para la violacion del check de "CUPO<=0", si me da Error "'297".

El codigo al final queda de esta forma:


except
on E:EFIBInterBaseError do
begin
datamodule1.Database2.Rollback;
if (E.SQLCode =-803) then
showmessage('Intenta crear un codigo de usuario que ya existe ')
else
if (E.SQLCode =-297) then
showmessage('El cupo asignado debe ser un valor mayor que cero');
end;
end;



La alternativa de Lepe es mas avanzada, no la comprendí (ando a un nivel bajo aun) y no se que Unidad soporta el literal: strDebug.

Bueno en todo caso AUN SIGO SIN PODER IDENTIFICAR ENTRE LOS DOS PRIMEROS ERRORES... En el librode firebird dice:

Error -297 : Operation violates CHECK Constraint
Error -803 : Violation of PRIMARY or UNIQUE KEY Constraint

Pero ya comprendo que cuando se produce el mensaje de error el dice que clase es y la traduccion del Codigo como parece lineas arriba, ademas ese mensaje me dice en que constrain ocurre (es decir conociendo la REstriccion, se que campo afecta) pero no se como obtener la restriccion.

Para ampliar mas,
Cuando se produce el Error -803 ademas del mensaje "Operation violates ....." me aparece que ocurre en PK_Clientes, (ese es el nombre del constrain para la clave primaria).


Mi pregunta ahora es....... Como obtengo el nombre de la Constraint.?

FelipeDiaz
14-12-2007, 22:19:16
Lo logre de esta forma, no se que tan buena sea....

Aprovechando que E.IBMessage, si me da el mensaje especifico incluyendo el nombre d ela Constraint, mientras que E.SQLMessage, me da uno generico sin detalles. y ademas utilizando la funcion POS.



try
Datamodule1.CLIENTES.Post;
CodBusCli:= Datamodule1.CLIENTESIDCLI.Value;
Datamodule1.Database2.Commit;
except
on E:EFIBInterBaseError do
begin
datamodule1.Database2.Rollback;
if (E.SQLCode =-803) then

if Pos('PK_CLIENTES', E.IBMessage) <> 0 then
showmessage('Intenta crear un codigo de Cliente que ya existe ')
else
if Pos('UNQ1_CLIENTES', E.IBMessage) <> 0 then
showmessage('El Nombre de cliente que ya existe ')

else
if (E.SQLCode =-297) then
showmessage('El cupo asignado debe ser un valor mayor que cero');
end;
end;



-------------------------------------------------------------

Bueno, hasta aqui va solo resuelta la primera parte ......falta la segunda parte del mensaje original ?

(a proposito, como hago para colocar aqui un cuadro con flecha azul ">", para crear un vinculo al mensaje)?

Lepe
14-12-2007, 22:47:05
En el campo:
EditFormat := '0.00'
DisplayFormat:= '0.00 %'

Solo verás el % mientras no tenga el cursor dentro del DBEdit.

Por cierto, a preguntas distintas, hilos distintos, espero lo recuerdes la próxima vez.

Saludos