unit uDataTableUtils; interface uses uDACDSDataTable, uDADataTable, uDAInterfaces; const ID_NULO = -9000; ID_TODOS = -9001; ID_PRIMERO = -9002; type TModoDuplicarRegistros = (mdrTodos, mdrActual, mdrSeleccionados); procedure CloneDataTable(const ASource : TDACDSDataTable; var ATarget : TDACDSDataTable; RemoteUpdate: Boolean = True); procedure DuplicarRegistro(ASource : TDADataTable; ATarget : TDADataTable); procedure DuplicarRegistros(ASource : TDADataTable; ATarget : TDADataTable; AModo : TModoDuplicarRegistros); procedure CopyDataTable(ASource : TDADataTable; ATarget : TDADataTable; const OnlySelectedRows : Boolean = False); procedure DeleteAllTable(const ADataTable : TDADataTable); function DeltaValuesAreDifferent(const aDelta : IDADelta): boolean; procedure EnlazarMaestroDetalle(AMasterDataSource : TDADataSource; ADetail : IDAStronglyTypedDataTable); implementation uses uDAClasses, SysUtils, uDABINAdapter, uROTypes, cxControls, Dialogs, Variants, uDBSelectionListUtils, uROClasses; {procedure EliminarNoSeleccionados(const ASource : IDADataset; var ATarget : TDADataTable); var AObj : ISelectedRowList; i : Integer; begin if not Supports(ASource, ISelectedRowList, aObj) then Exit; // ATarget.DisableControls; // ATarget.DisableEventHandlers; ShowHourglassCursor; try ATarget.Open; ATarget.Last; while ATarget.RecordCount > AObj.SelectedRows.Count do begin if AObj.SelectedRows.IndexOf(ATarget.RecIDValue) < 0 then ATarget.Delete else ATarget.Prior; end; finally // ATarget.EnableControls; // ATarget.EnableControls; HideHourglassCursor; end; end;} procedure DeleteAllTable(const ADataTable : TDADataTable); begin ADataTable.ClearRows; end; procedure CloneDataTable(const ASource : TDACDSDataTable; var ATarget : TDACDSDataTable; RemoteUpdate: Boolean); var i : Integer; begin with ATarget do begin RemoteService := ASource.GetRemoteService; Adapter := ASource.GetAdapter; //BusinessRulesID := ASource.BusinessRulesID; Randomize; Name := ASource.Name + '_' + IntToStr(Random(MAXINT)); LogicalName := ASource.LogicalName; Params.AssignParamCollection(ASource.Params); if Assigned(ASource.LocalSchema) then LocalSchema := ASource.LocalSchema else begin with SchemaCall do begin MethodName := ASource.SchemaCall.MethodName; for i := 0 to ASource.SchemaCall.Params.Count - 1 do begin with Params.Add do begin Name := ASource.SchemaCall.Params[i].Name; ParamType := ASource.SchemaCall.Params[i].ParamType; DataType := ASource.SchemaCall.Params[i].DataType; Value := ASource.SchemaCall.Params[i].Value; UserClassName := ASource.SchemaCall.Params[i].UserClassName; end; end; end; ATarget.Fields.AssignFieldCollection(ASource.Fields); // o también ATarget.LoadSchema; end; with DataUpdateCall do begin MethodName := ASource.DataUpdateCall.MethodName; for i := 0 to ASource.DataUpdateCall.Params.Count - 1 do begin with Params.Add do begin Name := ASource.DataUpdateCall.Params[i].Name; ParamType := ASource.DataUpdateCall.Params[i].ParamType; DataType := ASource.DataUpdateCall.Params[i].DataType; Value := ASource.DataUpdateCall.Params[i].Value; UserClassName := ASource.DataUpdateCall.Params[i].UserClassName; end; end; end; with ScriptCall do begin MethodName := ASource.ScriptCall.MethodName; for i := 0 to ASource.ScriptCall.Params.Count - 1 do begin with Params.Add do begin Name := ASource.ScriptCall.Params[i].Name; ParamType := ASource.ScriptCall.Params[i].ParamType; DataType := ASource.ScriptCall.Params[i].DataType; Value := ASource.ScriptCall.Params[i].Value; UserClassName := ASource.ScriptCall.Params[i].UserClassName; end; end; end; with DataRequestCall do begin MethodName := ASource.DataRequestCall.MethodName; for i := 0 to ASource.DataRequestCall.Params.Count - 1 do begin with Params.Add do begin begin Name := ASource.DataRequestCall.Params[i].Name; ParamType := ASource.DataRequestCall.Params[i].ParamType; DataType := ASource.DataRequestCall.Params[i].DataType; Value := ASource.DataRequestCall.Params[i].Value; UserClassName := ASource.DataRequestCall.Params[i].UserClassName; end; end; end; end; with MasterParamsMappings do for i := 0 to ASource.MasterParamsMappings.Count - 1 do Add(ASource.MasterParamsMappings.Strings[i]); with MasterRequestMappings do for i := 0 to ASource.MasterRequestMappings.Count - 1 do Add(ASource.MasterRequestMappings.Strings[i]); MasterMappingMode := ASource.MasterMappingMode; MasterFields := ASource.MasterFields; MasterOptions := ASource.MasterOptions; DetailFields := ASource.DetailFields; DetailOptions := ASource.DetailOptions; RemoteUpdatesOptions := ASource.RemoteUpdatesOptions; StreamingOptions := ASource.StreamingOptions; RemoteFetchEnabled := ASource.RemoteFetchEnabled; end; if not RemoteUpdate then begin ATarget.LogChanges := False; ATarget.RemoteFetchEnabled := False; end; end; function DeltaValuesAreDifferent(const aDelta : IDADelta): boolean; var i, x : integer; OldNewAreDifferent: boolean; begin OldNewAreDifferent := FALSE; for i := 0 to (aDelta.Count-1) do begin for x := 0 to (aDelta.LoggedFieldCount-1) do begin if aDelta.LoggedFieldTypes[x] <> datBlob then OldNewAreDifferent := (aDelta.Changes[i].OldValues[x] <> aDelta.Changes[i].NewValues[x]); if OldNewAreDifferent then Break; // Abandon iteration at the first difference between old and new. end; if OldNewAreDifferent then Break; // Abandon iteration at the first difference between old and new. end; result := OldNewAreDifferent; end; procedure CopyDataTable(ASource : TDADataTable; ATarget : TDADataTable; const OnlySelectedRows : Boolean = False); var DABin: Binary; DAAdapter : TDABINAdapter; AFilter : String; AFiltered : Boolean; AObj : ISelectedRecords; i : Integer; begin AFilter := ''; AFiltered := False; if OnlySelectedRows then begin if not Supports(ASource, ISelectedRecords, aObj) then raise Exception.Create('El origen de datos no soporta la interfaz ISelectedRecords (CopyDataTable)'); if ASource.Filtered then begin AFiltered := True; AFilter := ASource.Filter; ASource.Filtered := False; end; ASource.Filter := ''; if ASource.Active then ASource.Close; for i := 0 to AObj.Count - 1 do begin if (i > 0) then ASource.Filter := ASource.Filter + ' or '; ASource.Filter := ASource.Filter + '(ID = ' + IntToStr(AObj.Items[i]) + ')'; end; ASource.Filtered := True; end; DABin := Binary.Create; DAAdapter := TDABINAdapter.Create(nil); try ATarget.LogicalName := ASource.LogicalName; // We need to specify new dataset LogicalName ATarget.RemoteFetchEnabled := False; // "Desconectamos" la tabla destino del servidor if not ASource.Active then ASource.Open; ASource.First; DAAdapter.Initialize(DABin, aiWrite); DAAdapter.WriteDataset(DABin, ASource, [woRows]); DAAdapter.Initialize(DABin, aiReadFromBeginning); DAAdapter.ReadDataset(DABin, ATarget); DAAdapter.Finalize; ATarget.RemoteFetchEnabled := True; // "Conectamos" la tabla del servidor otra vez // Dejar el filtro de la tabla origen como estaba if OnlySelectedRows then begin ASource.Filtered := False; ASource.Filter := AFilter; if AFiltered then ASource.Filtered := True; end; finally FreeAndNil(DABin); FreeAndNil(DAAdapter); end; end; procedure DuplicarRegistro(ASource : TDADataTable; ATarget : TDADataTable); var i: Integer; ATargetField: TDAField; ASourceField: TDAField; ADetailFields : String; begin if not ASource.Active then ASource.Open; if not ASource.Active then ATarget.Open; // ¿ATarget es una tabla detalle? if Assigned(ATarget.MasterSource) then begin case ATarget.MasterMappingMode of //mmDataRequest: //Sin hacer; mmParams: ADetailFields := ATarget.DetailFields; end; end else ADetailFields := ''; ATarget.Insert; { Hay que desactivar los eventos para que dejan de funcionar las reglas de negocio y no nos interfieran en la copia de valores de los campos. } ATarget.DisableEventHandlers; try for i := 0 to ASource.Fields.Count - 1 do begin ASourceField := ASource.Fields[i]; ATargetField := ATarget.FindField(ASourceField.Name); if Assigned(ATargetField) then begin // Los campos AutoInc no se rellenan y tampoco los campos que // formen parte de la relación maestro-detalle en el // caso de que la tabla destino sea una tabla detalle. if (ATargetField.DataType <> datAutoInc) and (Pos(ATargetField.Name, ADetailFields) = 0) then ATargetField.Value := ASourceField.Value; end; end; finally ATarget.EnableEventHandlers; ATarget.Post; end; end; procedure DuplicarRegistros(ASource : TDADataTable; ATarget : TDADataTable; AModo : TModoDuplicarRegistros); begin if not ASource.Active then ASource.Open; if not ATarget.Active then ATarget.Open; if AModo = mdrActual then DuplicarRegistro(ASource, ATarget) //ATarget.CloneSelectedRecord(ASource, True) else begin ASource.First; while not ASource.EOF do begin DuplicarRegistro(ASource, ATarget); ASource.Next; end; end; end; procedure EnlazarMaestroDetalle(AMasterDataSource : TDADataSource; ADetail : IDAStronglyTypedDataTable); begin if Assigned(ADetail) then begin // ¡¡¡¡¡ MUY IMPORTANTE !!!!!!!!!!!!!!!!!! ADetail.DataTable.DisableEventHandlers; try ADetail.DataTable.MasterSource := AMasterDataSource; finally { Hay que activar los eventos porque dejan de funcionar las reglas de negocio al establecer la relación maestro-detalle. (Fallo de Data Abstract 3) } ADetail.DataTable.EnableEventHandlers; end; end; end; end.