unit uDataTableUtils; interface uses uDACDSDataTable, uDADataTable, uDAInterfaces, uDADelta, uDAMemDataTable; procedure CloneDataTable(const ASource : TDACDSDataTable; var ATarget : TDACDSDataTable; RemoteUpdate: Boolean = True); overload; function CloneDataTable(const ASource : TDAMemDataTable; RemoteUpdate: Boolean = True): TDAMemDataTable; overload; procedure CopyDataTable(ASource : IDADataset; ATarget : TDADataTable; const OnlySelectedRows : Boolean = False); procedure DeleteAllTable(const ADataTable : TDADataTable); function DeltaValuesAreDifferent(const aDelta : IDADelta): boolean; function DataTableModified (const ADataTable : TDADataTable): Boolean; implementation uses DB, Classes, uDAClasses, SysUtils, uDABINAdapter, uROTypes, uDBSelectionList, cxControls, Dialogs, Variants, uDADataStreamer; {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; 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 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 : IDADataset; ATarget : TDADataTable; const OnlySelectedRows : Boolean = False); var DABin: Binary; DAAdapter : TDABINAdapter; AFilter : String; AFiltered : Boolean; AObj : ISelectedRowList; i : Integer; begin DABin := Binary.Create; DAAdapter := TDABINAdapter.Create(nil); AFilter := ''; if OnlySelectedRows then begin if not Supports(ASource, ISelectedRowList, aObj) then raise Exception.Create('El origen de datos no soporta la interfaz ISelectedRowList (CopyDataTable)'); if ASource.Dataset.Filtered then begin AFiltered := True; AFilter := ASource.Dataset.Filter; ASource.Dataset.Filtered := False; end; ASource.Dataset.Filter := ''; for i := 0 to AObj.SelectedRows.Count - 1 do begin if (i > 0) then ASource.Dataset.Filter := ASource.Dataset.Filter + ' or '; ASource.Dataset.Filter := ASource.Dataset.Filter + '(RecID = ' + IntToStr(AObj.SelectedRows.Items[i]) + ')'; end; ASource.Dataset.Filtered := True; end; try ATarget.LogicalName := ASource.LogicalName; // We need to specify new dataset LogicalName if not ASource.Active then ASource.Open; ASource.Dataset.First; DAAdapter.WriteDataset(DABin, ASource, [woRows, woSchema], -1); DAAdapter.Initialize(DABin, aiReadFromBeginning); DAAdapter.ReadDataset(ATarget.LogicalName, ATarget, True, True); DAAdapter.Finalize; if OnlySelectedRows then begin ASource.Dataset.Filtered := False; ASource.Dataset.Filter := AFilter; if AFiltered then ASource.Dataset.Filtered := True; end; finally FreeAndNil(DABin); FreeAndNil(DAAdapter); end; end; function CloneDataTable(const ASource : TDAMemDataTable; RemoteUpdate: Boolean = True): TDAMemDataTable; var i : Integer; ATarget : TDAMemDataTable; begin if not Assigned(ASource) then raise Exception.Create ('No se ha asignado la tabla de origen (CloneDataTable)'); ATarget := TDAMemDataTable.Create(NIL); with ATarget do begin { ATENCIÓN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -------------------------------------------------------------------- DA5 tiene un fallo en el cual las tablas definidas como detalle no tienen asociados los eventos internos before... y after... por lo que los campos AutoInc no funcionan (no pone el -1, -2...). La forma de arreglarlo es llamar a DisableEventHandlers/EnableEventHandlers que realiza la asociación de los eventos. } ATarget.DisableEventHandlers; // <--- INDISPENSABLE!!!!!!!!!!!!!!!!!!!! try if not Assigned(ASource.RemoteDataAdapter) then raise Exception.Create('No está asignado RemoteDataAdapter (' + ASource.Name + ')'); LogicalName := ASource.LogicalName; CustomAttributes.Assign(ASource.CustomAttributes); Fields.AssignFieldCollection(ASource.Fields); // o también ATarget.LoadSchema; Params.AssignParamCollection(ASource.Params); RemoteDataAdapter := ASource.RemoteDataAdapter; Randomize; Name := ASource.Name + '_' + IntToStr(Random(MAXINT)); BusinessRulesID := ASource.BusinessRulesID; 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; finally ATarget.EnableEventHandlers; // <--- INDISPENSABLE!!!!!!!!!!!!!!!!!!!!!!!!! end; end; if not RemoteUpdate then begin ATarget.LogChanges := False; ATarget.RemoteFetchEnabled := False; end; Result := ATarget; end; procedure CloneDataTable(const ASource : TDACDSDataTable; var ATarget : TDACDSDataTable; RemoteUpdate: Boolean); var i : Integer; begin with ATarget do begin RemoteDataAdapter := ASource.RemoteDataAdapter; 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 ATarget.Fields.AssignFieldCollection(ASource.Fields); // o también ATarget.LoadSchema; 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 DataTableModified (const ADataTable : TDADataTable): Boolean; var bCambiado : Boolean; dtDetails : TList; i : integer; begin bCambiado := False; if Assigned(ADataTable) and (ADataTable.Active) then begin bCambiado :=(ADataTable.State = dsEdit) or (ADataTable.HasDelta and DeltaValuesAreDifferent(ADataTable.Delta)); if (not bCambiado) then begin dtDetails := ADataTable.GetDetailDataTables; for i := 0 to dtDetails.Count - 1 do begin bCambiado := bCambiado or ((TDADataTable(dtDetails.Items[i])).State in dsEditModes) or ((TDADataTable(dtDetails.Items[i])).HasDelta and DeltaValuesAreDifferent((TDADataTable(dtDetails.Items[i])).Delta)); if bCambiado then Break; end; end; end; Result := bCambiado; end; end.