PARTE II. Atomicidad de Transacciones usando un Array de ClientDataSets en Delphi

By: Jose Castillo Reyes

Abstract: En ésta segunda parte crearemos una aplicación que se conecte remotamente a nuestro servidor de aplicaciones.

    Introducción

Llego el momento de crear una aplicación que haga uso de nuestro servidor creado en la Parte I. En ella implementaremos una serie de métodos que nos permitirá armar y gestionar el array de ClientDataSets.

    El Cliente

Empecemos creando un proyecto siguiendo los siguientes pasos:

  • File -> New -> VCL Forms Applications – Delphi for win 32
  • Save All
  • El asistente solicitará el nombre de la unidad al cual la llamaremos: uMain.pas.
  • Luego, asignamos el nombre del proyecto: NTierXIClient.

    La unidad CDSUtil.pas

En ésta parte, debemos de añadir una unidad, en la que implementaremos unos métodos que se encargarán de armar y gestionar el envío del array de ClientDataSets con el Servidor remoto.

  • File -> New -> UnitDelphi for win 32

function RecuperarDeltas(const cdsArray : array of TClientDataset): Variant;

var

i : integer;

LowCDS, HighCDS : integer;

begin

Result:=NULL;

LowCDS:=Low(cdsArray);

HighCDS:=High(cdsArray);

for i:=LowCDS to HighCDS do

cdsArray[i].CheckBrowseMode;

Result:=VarArrayCreate([LowCDS, HighCDS], varVariant);

{Setea el variant con los cambios (o NULL si no hay ninguno)}

for i:=LowCDS to HighCDS do

begin

if cdsArray[i].ChangeCount>0 then

Result[i]:=cdsArray[i].Delta else

Result[i]:=NULL;

end;

end;

{Necesitamos devolver el nombre del Provider y el AppServer desde ésta función.

Utilizaremos ProviderName para llamar AS_ApplyUpdates en la función de CDSApplyUpdates después.}

function RecuperarProviders(const cdsArray : array of TClientDataset): Variant;

var

i: integer;

LowCDS, HighCDS: integer;

begin

Result:=NULL;

LowCDS:=Low(cdsArray);

HighCDS:=High(cdsArray);

Result:=VarArrayCreate([LowCDS, HighCDS], varVariant);

for i:=LowCDS to HighCDS do

Result[i]:=VarArrayOf([cdsArray[i].AppServer, cdsArray[i].ProviderName]);

end;

procedure ReconciliarDeltas(const cdsArray : array of TClientDataset; vDeltaArray: OleVariant);

var

bReconciliar : boolean;

i: integer;

LowCDS, HighCDS : integer;

begin

LowCDS:=Low(cdsArray);

HighCDS:=High(cdsArray);

{Si el paso anterior dió lugar a errores, Reconciliar los datapackets del error.}

bReconciliar:=false;

for i:=LowCDS to HighCDS do

if not VarIsNull(vDeltaArray[i]) then

begin

cdsArray[i].Reconcile(vDeltaArray[i]);

bReconciliar:=true;

break;

end;

{Actualizar los Datasets si es necesario}

if not bReconciliar then

for i:=HighCDS downto LowCDS do

begin

cdsArray[i].Reconcile(vDeltaArray[i]);

cdsArray[i].Refresh;

end;

end;

No olvide agregar en la cláusula uses las siguientes unidades: DbClient, ADODB, SysUtils, Provider, Midas y Variants.

    La Interfase del usuario

Llegó el momento de implementar la interfase de usuario, para ello colocaremos en el formulario los siguientes componentes:

2 TDBGrids (DBGridClientes y DBGridTerritorios)

2 TDBNavigators (DBNavigatorClientes y DBNavigatorTerritorios)

2 TClientDataSets (cdsMaster y cdsDetail)

2 TDataSources (dsMaster y dsDetail)

3 TButtons (btnCargarDatos, btnGuardar y btnCancelar)

2 TDBTexts (DBTextEstadoClientes y DBTextEstadoTerritorios)

1 TSocketConnection

Hide image
Click to see full-sized image

Para que nuestra aplicación se conecte remotamente con el servidor de aplicaciones, es necesario modificar algunas propiedades de nuestro componente SocketConnection, como se muestra en la siguiente figura:

Hide image

En la propiedad ServerName se muestran todos los servidores COM registrados en el servidor remoto,especificado en la propiedad Host. Para activar la conección, modificamos la propiedad Connected a true.

Nuestra aplicación cliente accederá al servidor usando el Borland Socket Server (aunque podría usarse también clientes DCOM o HTTP)

En el evento OnClick del botón btnCargarDatos escribimos el siguiente código:

cdsMaster.Active:= True;

cdsDetail.Active:= True;

Luego implementamos el código en el evento OnClick del botón btnGuardar:

procedure TForm3.btnGuardarClick(Sender: TObject);

var

vDeltaArray: OleVariant;

vProviderArray: OleVariant;

vCDSArray: array[0..1] of TClientDataset;

begin

vCDSArray[0]:=cdsMaster;

vCDSArray[1]:=cdsDetail;

vDeltaArray:=RecuperarDeltas(vCDSArray);

vProviderArray:=RecuperarProviders(vCDSArray);

//Llamamos al nuevo método del servidor, que implementamos en la Parte I.

SocketConnection.AppServer.CDSApplyUpdates(vDeltaArray, vProviderArray, False);

ReconciliarDeltas(vCDSArray, vDeltaArray);

end;

En el evento OnClick del botón btnCancelar escribimos el siguiente código:

cdsMaster.CancelUpdates;

cdsDetail.CancelUpdates;

Por último, compilamos la aplicación y lo echamos a correr, presionamos el botón Cargar datos para obtener los datos desde el servidor remoto, y luego modificamos los datos de las grillas y presionamos el botón Post del DBNavigator correspondiente. Luego para enviar los cambios al servidor presionamos el botón Guardar, es aquí donde se llama al método implementado en nuestro servidor (no confunda ApplyUpdates con nuestro nuevo método CDSApplyUpdates).

Hide image
Click to see full-sized image

Para controlar los errores de actualización de nuestros ClientDataSets vamos a añadir el código correspondiente en el evento OnReconcileError de nuestro componente cdsMaster:

Action := HandleReconcileError(DataSet, UpdateKind, E);

Hacemos lo mismo para el componente cdsDetail.

Para personalizar y rastrear las modificaciones realizadas en los ClientDataSet implementaremos un procedimiento que nos permita notificar visualmente ésta ocurrencia.

procedure TForm3.UpdateCalcFields(DataSet: TDataSet);

const

UpdateStatusStr: array[TUpdateStatus] of string = ( 'Sin modificar', 'Modificado',

'Insertado', 'Borrado');

begin

with Dataset as TClientDataset do

FieldByName('EstadoActual').Value := UpdateStatusStr[UpdateStatus];

end;

Previamente debimos haber creado un campo calculado llamado ’EstadoActual’, del tipo String y de 20 caracteres de tamaño.

    Conclusión

Con ésta segunda parte hemos intentado controlar la atomicidad de transacciones usando ClientDataSets con SQL Server. El código de la aplicación está disponible en la siguiente dirección: http://www.danysoft.com.

Server Response from: ETNASC03