PDA

Ver la Versión Completa : para no dejar duplicar registros en InterBase


Giniromero
17-06-2003, 12:36:59
Hola a todos,

Con interbase7 y delphi 6.

Tengo una ventana en mi aplicación que me sirve para agregar registros a una tabla. Esta tabla de interbase, tiene dos campos que son NO NULL y que juntos, son mi manera de direfenciar los registros de esa tabla.

Tengo un TDBNavigator para insertar, editar y gestionar en general esta tabla tbMaterial1.

El caso es que necesito poner una condición para que, si intenta alguien insertar un registro que ya esté, me muestre un mensaje de error, y no me deje guardar, me cancele la inserción.

El código que tengo es el siguiente:

procedure TFrmChangeMaterial.DBNavigator1BeforeAction(Sender: TObject;
Button: TNavigateBtn);
begin

If (FrmMainCenta.TbMaterial1.State = dsEdit) Or (FrmMainCenta.TbMaterial1.State = dsInsert) Then Begin
//si ya hay un material en la tabla material con los datos que estamos insertando nuevo
IF FrmMainCenta.TbMaterial.Locate ('ISBN;Copia', VarArrayOf([FrmMainCenta.TbMaterial1ISBN.AsVariant, FrmMainCenta.TbMaterial1Copia.AsVariant]), [locaseInsensitive]) THEN BEGIN
//If (FrmMainCenta.TbMaterial1.State = dsEdit) Or (FrmMainCenta.TbMaterial1.State = dsInsert) Then Begin
//mostramos mensaje aviso
showmessage ('¡¡CUIDADO!! El ISBN y COPIA insertados están asignados a otro material de la biblioteca. Su Operación no se puede llevar a cabo');
FrmMainCenta.IBTransCenta.Rollback;

END;
End;


end;


Donde TbMaterial1 y Tbmaterial funcionan como tablas independientes.

Me funciona, aparentemente todo bien hasta que muestra el mensaje, pero si después del mensaje pongo :
FrmMainCenta.IBTransCenta.Rollback; me dice que la tabla tbMaterial1 no esta en "edit o insert mode"

Si pongo
DBNavigator1.BtnClick(nbCancel); directamente no hace nada, me da el mismo error que cuando no le pongo código para controlar esto.:confused:



¿puede ayudarme alguien?

gracias

Virginia

kinobi
17-06-2003, 13:40:50
Hola,

¿y por qué no dejar que el servidor envíe el error de clave duplicada (si esos dos campos te sirven para diferenciar los registros de la tabla deben, o deberían ser clave principal de la misma), capturando la excepción en la aplicación Delphi?.

Creo que es mucho más sencillo y más rápido que tener un segundo DataSet para lanzar un Locate que busque una posible clave duplicada.

Saludos.

Giniromero
17-06-2003, 14:55:07
¿y como lo hago? porque, si dejo que salga el error este de, "duplicando registro", se me queda la aplicación colgadilla.:(

gracias por todo

Virginia

kinobi
17-06-2003, 15:11:31
Hola,

con try ... except. Ejemplo ...


try
...
// intento de envío de actualización al servidor
MiDataset.Post;
...
except
on E:EIBError do // error InterBase
begin
if E.IBError.Code = <codigo_error_clave_duplicada> then
// no recuerdo ahora cúal es, pero una
de las units de IBX tienes una constante
...
ShowMessage('Clave duplicada ...');
...
end;
Else Raise; // no es error InterBase
end;


Saludos.

digital
20-06-2003, 19:31:52
hola Kinobi
una duda.
las exception declaradas en la Base de datos se puede utilizar en el Ejemplo. que pones.

un ejemplo declaro una exception en la base de datos llamada
ART_NO_CODIGO con un texto 'NO HA INDICADO EL CODIGO DEL ARTICULO'

y despues creo un Trigger tipo Before Insert en la tabla de Articulos llamada.ARTICULOS_BI0

begin
if (new.codigo = "") then exception art_no_codigo;
end

la exception art_no_codigo se puede usar en try ... except.
try
MiDataset.Post;
except
on E:EIBError do
begin
if E.IBError.Code =art_no_codigo then
...
ShowMessage('Clave duplicada ...');
...
end;
Else Raise; end;

kinobi
21-06-2003, 02:05:03
Hola,

Posteado originalmente por digital
una duda.
las exception declaradas en la Base de datos se puede utilizar en el Ejemplo. que pones.

no a través del código de error. Para el caso de excepciones InterBase (CREATE EXCEPTION ....) la clase de excepciones EIBError recibe un código de error común para todas ellas, el valor 335544517 (si utilizas IBX tienes una constante definida para ese valor en la unit "IBErrorCodes.pas"; la constante es: "isc_except"). Por tanto no podrás discriminar entre excepciones utilizando el código de error enviado por el servidor. Pero sí puedes hacerlo a través del mensaje que devuelve, ya que es el mensaje de la excepción InterBase.

Por cierto, el código que puse anteriormente tiene un error. El código correcto es ...


try
...
// intento de envío de actualización al servidor
MiDataset.Post;
...
except
on E:EIBError do // error InterBase
begin
if E.IBErrorCode = isc_unique_key_violation
// la constante isc_unique_key_violation
// está definida en la unit IBErrorCodes (IBX)
...
ShowMessage('Clave duplicada ...');
// sustituir ShowMessage por el procesamiento que se desee
...
end;
else Raise; // no es error InterBase
end;


Para el caso de utilizar las cadenas de los mensajes de error de las excepciones InterBase ...


try
...
// intento de envío de actualización al servidor
MiDataset.Post;
...
except
on E:EIBError do // error InterBase
begin
if E.Message = <mensaje_excepción_InterBase>
...
ShowMessage(E.Message);
...
end;
else Raise; // no es error InterBase
end;


Saludos.