¡Hola a todos!
Cita:
Empezado por Al González
...ApplyUpdates sí genera excepciones pero las canaliza todas al evento OnReconcileError...
|
Cita:
Empezado por basti
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
...
Código Delphi [-]
try
ClientDataSet.ApplyUpdates(0);
except
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
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.