Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Conexión con bases de datos
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Conexión con bases de datos

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 29-08-2007
[David] David is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Málaga
Posts: 417
Poder: 21
David Va por buen camino
Cool Problema con excepciones con ClientDataSet

Hola

Tengo una función que devuelve un valor true o false , si se han podido o no grabar los datos .

Esto con Firebird , y tengo una TIBQuery , asociado el provider y el TClientDataSet y un componente TIBUpdateSQL para actualizar.

La tengo códificada algo así :

Código Delphi [-]
// Inicializo el resultado
Result := True;
// La funcion

// hago la inseción con el clientDataSet

// Hago el post
miClientDataSet.post;

miClientDataSet.ApplyUpdates(0);

Try
  IBTransaction1.Commit;
Except
  IBTransaction1.Rollback;
  Result := False;
end;

Pues bien , cuando me da una excepcion al pasar por miClientDataSet.ApplyUpdates(0); , no me entra en el Except y me devuelve True , en lugar de False y luego pues no puedo mostrar un mensaje al usuario , que saldria obviamente , cuando la función devuelva False y no True.

¿Qué es lo que falla en el código ?

Cómo deberia de poner dicha excepción ??


Un saludo
Responder Con Cita
  #2  
Antiguo 29-08-2007
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Hola David

Yo pienso que así estaría bien.

Código Delphi [-]
Result := True;
Try
  miClientDataSet.post;
  miClientDataSet.ApplyUpdates(0);
  IBTransaction1.Commit;
Except
  IBTransaction1.Rollback;
  Result := False;
end;

Salud OS
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #3  
Antiguo 29-08-2007
Avatar de Chris
[Chris] Chris is offline
Miembro Premium
 
Registrado: abr 2007
Ubicación: Jinotepe, Nicaragua
Posts: 1.678
Poder: 19
Chris Va por buen camino
Todo lo contrario

Solo cuando salga todo correcto es que el resultado debe ser true
Código Delphi [-]
Result := False;  // nunca sabemos que puede pasar.
Try
  miClientDataSet.post;
  miClientDataSet.ApplyUpdates(0);
  IBTransaction1.Commit;
  Result := True;  // todo ha salido bien
Except
  IBTransaction1.Rollback;
end;
__________________
Perfil Github - @chrramirez - Delphi Blog - Blog Web
Responder Con Cita
  #4  
Antiguo 29-08-2007
[David] David is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Málaga
Posts: 417
Poder: 21
David Va por buen camino
Digo yo , el post , tiene que estar dentro de la excepción ?

por que podria estar dentro de un bucle , algo así :

Código Delphi [-]
Result := False;

while not ClientDataSet.eof do
begin
 ClientDataSet.Insert;
 // asignaciones correspondientes
 ClientDataSet.post;
 ClientDataSet.Next;
end;

//
try
ClientDataSet.ApplyUpdates(0);
Transaction1.Commit;
Result := True;
except
Transaction1.Rollback;
end;

Es decir , como habeis dicho , pero el post lo dejo fuera del Try . Por si tuviera el caso de un bucle , que no es el caso que tengo ahora , pero me parece que tengos otros casos así.

Un saludo
Responder Con Cita
  #5  
Antiguo 29-08-2007
[basti] basti is offline
Miembro Premium
 
Registrado: ago 2004
Posts: 388
Poder: 20
basti Va por buen camino
ApplyUpdates no genera ninguna excepcion, devuelve el número de errores al actualizar los datos.

Código Delphi [-]
  if ClientDataSet.ApplyUpdates(0) > 0 then
  begin
    // entra aquí si hay errores
  end
  else begin
    // entra aquí si no hay errores
  end;
__________________
Saludos.
Responder Con Cita
  #6  
Antiguo 30-08-2007
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Smile

¡Hola a todos!

Basti: ApplyUpdates sí genera excepciones pero las canaliza todas al evento OnReconcileError. Es ahí donde David puede mostrar el mensaje al usuario.

Darwin: El código de Eliseo (Egostar) tendrá exactamente los mismos resultados que el tuyo, aunque quedaría mejor así:

Código Delphi [-]
  miClientDataSet.Post;
  
  If miClientDataSet.ApplyUpdates (0) = 0 Then
  Begin
    IBTransaction1.Commit;
    Result := True;  // El registro se aplicó sin problemas
  End
  Else
  Begin
    IBTransaction1.Rollback;
    Result := False;  // Algo salió mal al intentar aplicar el registro
  End;

Un abrazo cometido.

Al González.
Responder Con Cita
  #7  
Antiguo 30-08-2007
[basti] basti is offline
Miembro Premium
 
Registrado: ago 2004
Posts: 388
Poder: 20
basti Va por buen camino
Cita:
Empezado por Al González Ver Mensaje
ApplyUpdates sí genera excepciones pero las canaliza todas al evento OnReconcileError.
No estoy de todo de acuerdo con eso. ApplyUpdates gestiona los posibles errores a través de OnReconcileError, pero no genera ninguna excepción.

Código Delphi [-]
  try
    ClientDataSet.ApplyUpdates(0);
  except
    // Aquí no entraría nunca, haya o no haya errores.
  end;
__________________
Saludos.
Responder Con Cita
  #8  
Antiguo 30-08-2007
[David] David is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Málaga
Posts: 417
Poder: 21
David Va por buen camino
El caso es que la estructura del programa es algo así , con ClientDataSet de detalle .

Código Delphi [-]
// inserto los datos en un ClientDataSet , por ejemplo Client1
Client1.post.

// compruebo si el detalle tiene datos

if not ClientDetalle.isEmpty then
begin
 while not ClientDetalle.eof do
  begin
    // inserto los registros
     ClientDetalle.post;
 end;
end;

// Después haria supongo esto

if (Client1.ApplyUpdates(0) = 0) and (ClientDetalle.ApplyUpdate(0)=0) then
begin
 Commit;
 Result := True;
end
else
begin
 Rollback;
 Result := False;
end;

Bueno , pues eso , ya para poner el código definitivo , me gustaria saber si lo anterior por lo que habeis comentado es ya lo correcto.
Responder Con Cita
  #9  
Antiguo 30-08-2007
[pepon386] pepon386 is offline
Miembro Premium
 
Registrado: ene 2005
Ubicación: Valencia
Posts: 68
Poder: 20
pepon386 Va por buen camino
Una cosa, cuando haces esto:
Código Delphi [-]
if (Client1.ApplyUpdates(0) = 0) and (ClientDetalle.ApplyUpdate(0)=0) then
begin
 Commit; <-------------
 Result := True;
end
else
begin
 Rollback; <--------------
 Result := False;
end;

si mal no recuerdo, al llamar a ApplyUpdates, en este método inicia una transacción, realiza los cambios que hay pendientes en el Delta del ClientDataSet y, si todo ha ido bien, efectúa el Commit de la transacción. En caso contrario, si se ha quedado algún error (no ha sido gestionado en el evento OnReconcileError) entonces hace un Rollback de la transacción.
Repito que escribo de memoria, pero más o menos es así, con lo que el Commit y Rollback del ejemplo sobran.
Responder Con Cita
  #10  
Antiguo 30-08-2007
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Smile Algunos apuntes sobre las transacciones al usar TClientDataSet

¡Hola a todos!

Cita:
Empezado por Al González Ver Mensaje
...ApplyUpdates sí genera excepciones pero las canaliza todas al evento OnReconcileError...
Cita:
Empezado por basti Ver Mensaje
No estoy de todo de acuerdo con eso. ApplyUpdates gestiona los posibles errores a través de OnReconcileError, pero no genera ninguna excepción...
Aquí la sentencia donde, a través del método ReconcileCallback, ApplyUpdates genera (crea) las excepciones relacionadas con problemas al aplicar los datos (línea 1833 de DBClient.pas en Delphi 7):
Código Delphi [-]
    E := EReconcileError.Create(pErrMessage, pErrContext, iErrCode, iRslt);

Ciertamente no eleva (Raise) tal excepción, pero si envía el objeto como parámetro al evento OnReconcileError (línea 1850):
Código Delphi [-]
        FOnReconcileError(DataSet, E, UpdateKind, Action);

Por lo tanto es correcto que tal excepción no sale elevada fuera del método ApplyUpdates, como bien lo ilustras en este código donde me permití agregar una línea al comentario:
Cita:
Empezado por basti Ver Mensaje
...
Código Delphi [-]
  try
    ClientDataSet.ApplyUpdates(0);
  except
    // Aquí no entraría nunca, haya o no haya errores
    // —de los que crea ReconcileCallback—.
  end;
En concluyente pues, que de nada sirve usar un bloque Try-Except para atrapar las excepciones de clase EReconcileError, puesto que éstas no son elevadas. Por otra parte, la recomendación que hago de usar If sobre ApplyUpdates presenta un par de detalles interesantes cuando se considera algo como esto:

Cita:
Empezado por pepon386 Ver Mensaje
Una cosa, cuando haces esto:
Código Delphi [-]
if (Client1.ApplyUpdates(0) = 0) and (ClientDetalle.ApplyUpdates(0)=0) then
begin
 Commit; <-------------
 Result := True;
end
else
begin
 Rollback; <--------------
 Result := False;
end;

si mal no recuerdo, al llamar a ApplyUpdates, en este método inicia una transacción, realiza los cambios que hay pendientes en el Delta del ClientDataSet y, si todo ha ido bien, efectúa el Commit de la transacción. En caso contrario, si se ha quedado algún error (no ha sido gestionado en el evento OnReconcileError) entonces hace un Rollback de la transacción.
Repito que escribo de memoria, pero más o menos es así, con lo que el Commit y Rollback del ejemplo sobran.
Lo que dice Pepon386 es hasta cierto punto verdadero, digo esto porque depende del componente proveedor utilizado y de si la conexión ya está dentro de una transacción o no. Es el componente TDataSetProvider, en su método InternalApplyUpdates (línea 2618 de Provider.pas en Delphi 7), quien maneja el guardado de los datos de manera transaccional (inicia transacción, aplica los datos y comete la transacción o bien la revierte si ocurre un problema). Pero sólo lo hace si la conexión a la base de datos no está ya dentro de una transacción.

Dejar que el proveedor maneje la transacción no es útil cuando queremos involucrar dos o más conjuntos de datos clientes en una sola transacción, como es el caso actual de David, donde hace bien en iniciar él mismo la transacción de manera explícita. Sin embargo esta útil opción tiene un precio incómodo:

Si Client1.ApplyUpdates(0) devuelve 0 y ClientDetalle.ApplyUpdates(0) no, es claro que la transacción ha de ser revertida (Rollback) en el Else. Pero Client1 se quedará con la idea de que los datos aplicados siguen vigentes (su propiedad ChangeCount habrá sido restablecida a 0). Esto obliga a emplear un Client1.Refresh o algún mecanismo similar para reubicar a Client1 en la realidad; y si lo utilizado para ello fue una llamada al método Refresh, ¿qué pasa con lo que ya se había asignado al registro? A menos que algo se me escape, tales datos se pierden.

Claro, siempre será posible conservar una copia de los datos en alguna variable o algo por el estilo (incluso esto puede convertirse en un pretexto más para los dataawarefóbicos), finalmente Delphi, a diferencia de otros lenguajes, tiene solución para todo.

Como comentario extra, hace tiempo vengo agregando nuevas características a derivados de TClientDataSet, TDataSetProvider y otros componentes de acceso a datos. Actualmente trabajo en un mecanismo que permitirá conservar la propiedad ChangeCount aún después de haber hecho un ApplyUpdates exitoso, esto con el fin de manejar varios conjuntos de datos clientes en el contexto de una transacción del servidor de manera más sencilla y consistente.

Un abrazo transaccional.

Al González.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Problema manejando excepciones David OOP 1 28-07-2006 19:17:48
Problema con excepciones soto Varios 5 15-12-2005 18:26:40
Problema con ClientDataSet kaopectate Conexión con bases de datos 3 13-02-2005 22:08:57
Problema con las Excepciones y OO kueik Varios 4 18-06-2004 14:05:34
Problema de ClientDAtaset con xml carlosmoralesm Internet 6 03-03-2004 21:46:16


La franja horaria es GMT +2. Ahora son las 11:00:11.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi