Componentes.Terceros.RemObj.../internal/5.0.35.741/1/Data Abstract for Delphi/Source/uDARemoteDataAdapter.pas

933 lines
36 KiB
ObjectPascal

unit uDARemoteDataAdapter;
{----------------------------------------------------------------------------}
{ Data Abstract Library - Core Library }
{ }
{ compiler: Delphi 6 and up, Kylix 3 and up }
{ platform: Win32, Linux }
{ }
{ (c)opyright RemObjects Software. all rights reserved. }
{ }
{ Using this code requires a valid license of the Data Abstract }
{ which can be obtained at http://www.remobjects.com. }
{----------------------------------------------------------------------------}
{$I DataAbstract.inc}
interface
uses
Classes,
uRODynamicRequest, uRORemoteService, uROTypes, uROClasses,
uDAInterfaces, uDAClasses, uDADataStreamer, uDADataTable,
uDARemoteDataAdapterRequests, DataAbstract4_Intf;
// for backward compatibility
const
fbNone = uDADataTable.fbNone;
fbRaiseException = uDADataTable.fbRaiseException;
fbShowReconcile = uDADataTable.fbShowReconcile;
fbBoth = uDADataTable.fbBoth;
rdlgNone = uDADataTable.rdlgNone;
rdlgSkip = uDADataTable.rdlgSkip;
rdlgCancel = uDADataTable.rdlgCancel;
rdlgRepost = uDADataTable.rdlgRepost;
rdlgRevert = uDADataTable.rdlgRevert;
type
TDAApplyUpdatesEvent = uDADataTable.TDAApplyUpdatesEvent;
TDAFailureBehavior = uDADataTable.TDAFailureBehavior;
TDABeforeProcessFailuresEvent = uDADataTable.TDABeforeProcessFailuresEvent;
TDAOnGenerateRecordMessage = uDADataTable.TDAOnGenerateRecordMessage;
TDAShowReconcleDialogEvent = uDADataTable.TDAShowReconcleDialogEvent;
TDAShowReconcileRecordInAppUIEvent = uDADataTable.TDAShowReconcileRecordInAppUIEvent;
TDAReconcileDialogAction = uDADataTable.TDAReconcileDialogAction;
// end for backward compatibility
type
TDARequestEvent = procedure(Sender: TObject; Request: TRODynamicRequest) of object;
{ TDARemoteDataAdapter }
TDARemoteDataAdapter = class(TDABaseRemoteDataAdapter)
private
fGetDataCall: TDAGetDataRequest;
fGetSchemaCall: TDAGetSchemaRequest;
fUpdateDataCall: TDAUpdateDataRequest;
fGetScriptsCall: TDAGetScriptsRequest;
fRemoteService: TRORemoteService;
fSchema: TDASchema;
fCacheSchema: boolean;
fBeforeGetDataCall, fAfterGetDataCall,
fBeforeGetSchemaCall, fAfterGetSchemaCall,
fBeforeGetScriptsCall, fAfterGetScriptsCall,
fBeforeUpdateDataCall, fAfterUpdateDataCall: TDARequestEvent;
procedure SetCacheSchema(const Value: boolean);
function CreateTableRequestInfo(aTable: TDADataTable; aIncludeSchema: boolean; aDynamicWhereExpression: TDAWhereExpression = nil): TableRequestInfo;
procedure DoGetSchemaCall;
procedure FillTableNamesParam(aTables: array of TDADataTable; aParam: TRORequestParam);
procedure SetRemoteService(const Value: TRORemoteService);
procedure FillTableParams(aTables: array of TDADataTable; aParam: TRORequestParam);
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure Loaded; override;
function InternalFillSchema: TRODataType; override;
procedure InternalFillSchema_ClearParams; override;
function InternalApplyUpdates(aTables,aTablesWithDetails: array of TDADataTable): boolean; override;
procedure InternalReconcileDialog(RemoteDataAdapter: TDABaseRemoteDataAdapter; var AFailedDeltaList: TList; aTableList: TList);override;
function GetSchemaStream: Binary; override;
{ backward compatibility: to provide access to these in the legacy events in TDADataTable}
function Get_GetSchemaCall: TDARemoteRequest; override;
function Get_GetDataCall: TDARemoteRequest; override;
function Get_UpdateDataCall: TDARemoteRequest; override;
function Get_GetScriptsCall: TDARemoteRequest; override;
function GetSchema: TDASchema; override;
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
procedure SetupDefaultRequestV3;
procedure SetupDefaultRequest;
procedure CheckProperties; override;
procedure Fill(aTables: array of TDADataTable; aSaveCursor: boolean=false; aIncludeSchema: boolean=false); overload; override;
procedure Fill(aTables: array of TDADataTable; aTableRequestInfoArray: array of TableRequestInfo; aSaveCursor: boolean=false; aIncludeSchema: boolean=false); overload; override;
procedure Fill(aTables: array of TDADataTable; aWhereClauses : array of TDAWhereExpression; aSaveCursor: boolean=false; aIncludeSchema: boolean=false); overload; override;
// procedure FillSchema(aTables: array of TDADataTable; aPreserveLookupFields: boolean = false; aPreserveClientCalcFields : boolean = false); override;
procedure FillScripts(aTables: array of TDADataTable); override;
function ReadSchema(aForceReRead: boolean = false): TDASchema;override;
procedure FlushSchema;
property Schema: TDASchema read GetSchema;
published
property GetSchemaCall: TDAGetSchemaRequest read fGetSchemaCall;
property GetDataCall: TDAGetDataRequest read fGetDataCall;
property UpdateDataCall: TDAUpdateDataRequest read fUpdateDataCall;
property GetScriptsCall: TDAGetScriptsRequest read fGetScriptsCall;
property RemoteService: TRORemoteService read fRemoteService write SetRemoteService;
property CacheSchema: boolean read fCacheSchema write SetCacheSchema default false;
property BeforeGetDataCall: TDARequestEvent read fBeforeGetDataCall write fBeforeGetDataCall;
property AfterGetDataCall: TDARequestEvent read fAfterGetDataCall write fAfterGetDataCall;
property BeforeGetSchemaCall: TDARequestEvent read fBeforeGetSchemaCall write fBeforeGetSchemaCall;
property AfterGetSchemaCall: TDARequestEvent read fAfterGetSchemaCall write fAfterGetSchemaCall;
property BeforeGetScriptsCall: TDARequestEvent read fBeforeGetScriptsCall write fBeforeGetScriptsCall;
property AfterGetScriptsCall: TDARequestEvent read fAfterGetScriptsCall write fAfterGetScriptsCall;
property BeforeUpdateDataCall: TDARequestEvent read fBeforeUpdateDataCall write fBeforeUpdateDataCall;
property AfterUpdateDataCall: TDARequestEvent read fAfterUpdateDataCall write fAfterUpdateDataCall;
end;
implementation
uses
SysUtils, DB, TypInfo, Variants,
uRODL, uROXMLIntf, uDAReconcileDialog, uROBinaryHelpers;
{ TDARemoteDataAdapter }
procedure TDARemoteDataAdapter.FillTableNamesParam(aTables: array of TDADataTable; aParam: TRORequestParam);
var
lArray: StringArray;
i: integer;
begin
case aParam.DataType of
rtString: begin // v3 style string
if Length(aTables) <> 1 then
raise Exception.Create('The current GetDataCall configuration does not allow fetching multiple data tables at once.');
aParam.AsString := aTables[Low(aTables)].LogicalName;
end;
rtUserDefined: begin // v4 style string array
lArray := StringArray.Create();
lArray.Resize(Length(aTables));
for i := Low(aTables) to High(aTables) do
lArray[i-Low(aTables)] := AnsiToUtf8(aTables[i].LogicalName);
aParam.AsComplexType := lArray;
aParam.OwnsComplexType := true;
end;
end;
end;
procedure TDARemoteDataAdapter.FillTableParams(
aTables: array of TDADataTable; aParam: TRORequestParam);
var
lArray: DataParameterArray;
lParam: DataParameter;
lTable: TDADataTable;
j: integer;
lList: TStringList;
begin
lArray:=nil; // prevert "W1036 Variable 'lArray' might not have been initialized"
case aParam.DataType of
rtString: begin // v3 style string
if Length(aTables) <> 1 then raise Exception.Create('The current GetDataCall configuration does not allow fetching multiple data tables');
with aTables[Low(aTables)].Params do begin
if Count<>0 then begin
lList:= TStringList.Create;
try
for j := 0 to Count - 1 do
lList.Values[Params[j].Name]:=Params[j].AsString;
aParam.AsString:= lList.Text;
finally
lList.Free;
end;
end;
end;
end;
rtUserDefined: begin
if aParam.TypeName = 'DataParameterArray' then
lArray := DataParameterArray.Create();
lTable := aTables[Low(aTables)];
for j := 0 to lTable.Params.Count-1 do begin
lParam := lArray.Add();
lParam.Name := AnsiToUtf8(lTable.Params[j].Name);
lParam.Value := lTable.Params[j].Value;
end;
aParam.AsComplexType := lArray;
aParam.OwnsComplexType := true;
end;
end;
end;
procedure TDARemoteDataAdapter.Fill(aTables: array of TDADataTable; aTableRequestInfoArray: array of TableRequestInfo; aSaveCursor: boolean=false; aIncludeSchema: boolean=false);
var
lSavedOptions: array of TDATableOptions;
lHasTableNamesParameter: Boolean;
lParam, lResultParam: TRORequestParam;
i: integer;
ltablearray: array of TDADataTable;
ltableList: TList;
llocalList: TList;
ltbl: TDADataTable;
lArray: TableRequestInfoArray;
begin
if Length(aTables) <> Length(aTableRequestInfoArray) then raise Exception.Create('aTables and aTableRequestInfoArray should contain equal members count.');
CheckProperties;
lArray:= TableRequestInfoArray.Create;
try
ltableList := TList.Create;
llocalList := TList.Create;
try
for i := Low(aTables) to High(aTables) do begin
ltbl:=aTables[i];
if ltbl = nil then continue;
if ltableList.IndexOf(ltbl) = -1 then ltableList.Add(ltbl);
ltbl.GetDetailTablesforAllinOneFetch(ltableList,llocalList,True);
end;
SetLength(ltablearray,ltableList.Count);
for i := 0 to ltableList.Count - 1 do
ltablearray[i]:=TDADataTable(ltableList[i]);
for i := 0 to High(ltablearray) do
lArray.Add(nil);
for i := 0 to High(aTableRequestInfoArray) do
lArray.Items[ltableList.IndexOf(aTables[i])]:=aTableRequestInfoArray[i];
for i := 0 to lArray.Count-1 do
if lArray.Items[i] = nil then lArray.Items[i]:= CreateTableRequestInfo(ltablearray[i],aIncludeSchema);
finally
ltableList.Free;
llocalList.Free;
end;
if length(ltablearray) = 0 then Exit;
SetLength(lSavedOptions, length(ltablearray));
try
for i := 0 to High(ltablearray) do begin
ltbl:= ltablearray[i];
lSavedOptions[i].OldLogChanges := ltbl.LogChanges;
ltbl.LogChanges := false;
ltbl.InternalSetFetching(true);
if ltbl.Active then begin
lSavedOptions[i].GoFirst := false;
if aSaveCursor then
lSavedOptions[i].Bookmark := ltbl.GetBookMark;
end
else begin
lSavedOptions[i].GoFirst := true;
end;
end;
try
lParam := GetDataCall.Params.FindParam(GetDataCall.OutgoingTableNamesParameter);
lHasTableNamesParameter := assigned(lParam);
if lHasTableNamesParameter then
FillTableNamesParam(ltablearray, lParam)
else if Length(ltablearray) <> 1 then
raise Exception.Create('The current GetDataCall configuration does not allow fetching multiple data tables');
if Length(GetDataCall.OutgoingTableRequestInfosParameter) > 0 then begin
lParam := GetDataCall.Params.FindParam(GetDataCall.OutgoingTableRequestInfosParameter);
if Assigned(lParam) then begin
if (lParam.DataType = rtUserDefined) and (lParam.TypeName = 'TableRequestInfoArray') then begin
lParam.AsComplexType := lArray;
end;
end;
end;
if (GetDataCall.OutgoingParamsParameter <> '') then begin // v3 style call
lParam := GetDataCall.Params.FindParam(GetDataCall.OutgoingParamsParameter);
if Assigned(lParam) then
FillTableParams(ltablearray, lParam);
end;
if (GetDataCall.OutgoingMaxRecordsParameter <> '') then begin // v3 style call
if Length(ltablearray) <> 1 then
for i := 0 to High(ltablearray) do
if ltablearray[i].MaxRecords <> -1 then
raise Exception.Create('The current GetDataCall configuration does not allow fetching multiple data tables with a limited record count.');
lParam := GetDataCall.Params.FindParam(GetDataCall.OutgoingMaxRecordsParameter);
if Assigned(lParam) and (Length(ltablearray) > 0) then lParam.AsInteger := ltablearray[0].MaxRecords;
end;
if (GetDataCall.OutgoingIncludeSchemaParameter <> '') then begin // v3 style call
lParam := GetDataCall.Params.FindParam(GetDataCall.OutgoingIncludeSchemaParameter);
if Assigned(lParam) then lParam.AsBoolean := aIncludeSchema;
end;
if Assigned(fBeforeGetDataCall) then fBeforeGetDataCall(Self, GetDataCall);
GetDataCall.Execute();
lResultParam := GetDataCall.Params.FindParam(GetDataCall.IncomingDataParameter);
if Assigned(fAfterGetDataCall) then fAfterGetDataCall(Self, GetDataCall);
if not assigned(lResultParam) or (lResultParam.DataType <> rtBinary) then
raise Exception.Create('Result parameter of GetDataCall is not properly defined.');
if not assigned(lResultParam.AsBinary) then raise Exception.Create('The server returned a nil buffer.');
{todo?: oldpos := lResultParam.AsBinary.Position;
if Assigned(fOnAfterDataRequestCall) then fOnAfterDataRequestCall(Self, DataRequestCall);
if Assigned(fOnReceiveDataStream) then fOnReceiveDataStream(Self, data);
lResultParam.AsBinary.Position := oldpos;}
// Reads the data
DataStreamer.Initialize(lResultParam.AsBinary, aiRead);
try
// part 1 - reading schema
for i := Low(ltablearray) to High(ltablearray) do
begin
//if aTables[i].Opening then begin
ltbl:= ltablearray[i];
if lArray[i].IncludeSchema and not (soIgnoreStreamSchema in ltbl.StreamingOptions) then begin
if not lHasTableNamesParameter and (DataStreamer.DatasetCount = 1) then
DataStreamer.ReadDataset(DataStreamer.DatasetNames[0], ltbl, true, false)
else
DataStreamer.ReadDataset(ltbl.LogicalName, ltbl, true, false);
end;
if not ltbl.Active then ltbl.InitializeDataTable;
//end;
end;
// part 2 - reading data
for i := Low(ltablearray) to High(ltablearray) do begin
ltbl:= ltablearray[i];
if not lHasTableNamesParameter and (DataStreamer.DatasetCount = 1) then
DataStreamer.ReadDataset(DataStreamer.DatasetNames[0], ltbl, false, true)
else
DataStreamer.ReadDataset(ltbl.LogicalName, ltbl, false, true);
if (moAllInOneFetch in ltbl.MasterOptions) then begin
ltbl.DoCascadeOperation(DataStreamer, moAllInOneFetch);
end;
end;
finally
DataStreamer.Finalize;
end;
finally
lParam := GetDataCall.Params.FindParam(GetDataCall.OutgoingTableRequestInfosParameter);
if Assigned(lParam) then lParam.ClearValue;
lParam := GetDataCall.Params.FindParam(GetDataCall.OutgoingParamsParameter);
if Assigned(lParam) then lParam.ClearValue;
lParam := GetDataCall.Params.FindParam(GetDataCall.IncomingDataParameter);
if Assigned(lParam) then lParam.ClearValue;
for i := 0 to High(ltablearray) do begin
ltbl:= ltablearray[i];
if ltbl.Active then begin
if lSavedOptions[i].GoFirst then begin
ltbl.First;
end
else begin
if aSaveCursor then begin
ltbl.GotoBookmark(lSavedOptions[i].Bookmark);
ltbl.FreeBookmark(lSavedOptions[i].Bookmark);
end;
end;
end;
ltbl.LogChanges := lSavedOptions[i].OldLogChanges;
ltbl.InternalSetFetching(false);
end;
end;
if AutoFillScripts then FillScripts(ltablearray);
finally
SetLength(lSavedOptions,0);
SetLength(ltablearray,0);
end;
finally
lArray.Free;
end;
end;
procedure TDARemoteDataAdapter.DoGetSchemaCall;
begin
//ToDo: handle aFilter parameter?
if Assigned(fBeforeGetSchemaCall) then fBeforeGetSchemaCall(Self, GetSchemaCall);
GetSchemaCall.Execute();
if Assigned(fAfterGetSchemaCall) then fAfterGetSchemaCall(Self, GetSchemaCall);
end;
procedure TDARemoteDataAdapter.Fill(aTables: array of TDADataTable; aSaveCursor: boolean=false; aIncludeSchema: boolean=false);
var
lTableRequestInfoArray: array of TableRequestInfo;
lTables: array of TDADataTable;
i,j: integer;
begin
SetLength(lTableRequestInfoArray, Length(aTables));
SetLength(lTables, Length(aTables));
j:=0;
for i := 0 to High(aTables) do begin
if aTables[i] <> nil then begin
lTables[j]:=aTables[i];
lTableRequestInfoArray[j]:= CreateTableRequestInfo(aTables[j],aIncludeSchema);
inc(j);
end;
end;
SetLength(lTables, j);
SetLength(lTableRequestInfoArray, j);
Fill(lTables, lTableRequestInfoArray, aSaveCursor, aIncludeSchema);
end;
procedure TDARemoteDataAdapter.Fill(aTables: array of TDADataTable; aWhereClauses: array of TDAWhereExpression; aSaveCursor, aIncludeSchema: boolean);
var
lTableRequestInfoArray: array of TableRequestInfo;
lTables: array of TDADataTable;
i,j: integer;
begin
if Length(aTables) <> Length(aWhereClauses) then raise Exception.Create('aTables and aWhereClauses should contain equal members count.');
SetLength(lTableRequestInfoArray, Length(aTables));
SetLength(lTables, Length(aTables));
j:=0;
for i := 0 to High(aTables) do begin
if aTables[i] <> nil then begin
lTables[j]:=aTables[i];
lTableRequestInfoArray[j]:= CreateTableRequestInfo(aTables[j],aIncludeSchema, aWhereClauses[i]);
inc(j);
end;
end;
SetLength(lTables, j);
SetLength(lTableRequestInfoArray, j);
Fill(lTables, lTableRequestInfoArray, aSaveCursor,aIncludeSchema);
end;
(*
procedure TDARemoteDataAdapter.FillSchema(aTables: array of TDADataTable; aPreserveLookupFields, aPreserveClientCalcFields: boolean);
type
THandlerArray = array[0..1] of TMethod;
PHandlerArray = ^THandlerArray;
const
HandlersToSave : array[0..1] of string = ('OnChange', 'OnValidate');
var
lSavedOptions: array of TDATableOptions;
i, j, k, lIndex: integer;
lHandlers : PHandlerArray;
lResultParam: TRORequestParam;
lSchema: TDASchema;
lDataTableSchema: TDADataset;
lookupfields : TDAFieldCollection;
clientcalcfields : TDAFieldCollection;
lField: TDAField;
begin
CheckProperties;
SetLength(lSavedOptions, Length(aTables));
for i := Low(aTables) to High(aTables) do
if aTables[i].Active then aTables[i].Close();
lookupfields := nil;
clientcalcfields := nil;
for i := Low(aTables) to High(aTables) do
aTables[i].Fields.FieldEventsDisabled := true;
try
for i := Low(aTables) to High(aTables) do begin
lSavedOptions[i-Low(aTables)].FieldHandlers := TStringList.Create;
{ Saves the current event handler pointers }
for j := 0 to aTables[i].Fields.Count-1 do begin
New(lHandlers);
for k := Low(HandlersToSave) to High(HandlersToSave) do
lHandlers[k] := GetMethodProp(aTables[i].Fields[j], HandlersToSave[k]);
lSavedOptions[i-Low(aTables)].FieldHandlers.AddObject(aTables[i].Fields[j].Name, TObject(lHandlers));
end;
{ Save lookup and calced fields}
if aPreserveLookupFields then begin
lookupfields := TDAFieldCollection.Create(nil);
lookupfields.Assign(aTables[i].Fields);
for j := (lookupfields.Count-1) downto 0 do
if not (lookupfields[j] as TDACustomField).Lookup then
lookupfields.Delete(j);
end;
if aPreserveClientCalcFields then begin
clientcalcfields := TDAFieldCollection.Create(nil);
clientcalcfields.Assign(aTables[i].Fields);
for j :=(clientcalcfields.Count-1) downto 0 do
if not (clientcalcfields[j] as TDACustomField).Calculated then
clientcalcfields.Delete(j);
end;
aTables[i].Fields.Clear;
end;
try
lResultParam := GetSchemaCall.Params.FindParam(GetSchemaCall.IncomingSchemaParameter);
if not assigned(lResultParam) then
raise Exception.Create('Result parameter of GetSchemaCall is not defined.');
case lResultParam.DataType of
rtBinary:begin
DoGetSchemaCall();
if not assigned(lResultParam.AsBinary) or (lResultParam.AsBinary.Size = 0 ) then
raise Exception.Create('Server returned an empty buffer for schema.');
DataStreamer.Initialize(lResultParam.AsBinary, aiRead);
try
if (DataStreamer.DatasetCount = 0) then raise Exception.Create('Stream does not contain any dataset');
for i := Low(aTables) to High(aTables) do
DataStreamer.ReadDataset(aTables[i].LogicalName, aTables[i], true, false);
finally
DataStreamer.Finalize;
end;
end;
rtString:begin
lSchema := Schema;
for i := Low(aTables) to High(aTables) do begin
lDataTableSchema := lSchema.Datasets.FindDatasetByName(aTables[i].LogicalName);
if not assigned(lDataTableSchema) then
lDataTableSchema := lSchema.UnionDataTables.FindUnionDataTableByName(aTables[i].LogicalName);
if not assigned(lDataTableSchema) then
lDataTableSchema := lSchema.JoinDataTables.FindJoinTableByName(aTables[i].LogicalName);
if not assigned(lDataTableSchema) then raise Exception.CreateFmt('Data table "%s" was not found in schema.',[aTables[i].LogicalName]);
aTables[i].Fields.AssignFieldCollection(lDataTableSchema.Fields);
// ToDo: the code below is shared with TableWizard. Refactor.
if lDataTableSchema is TDAUnionDataTable then begin
if not Assigned(aTables[i].Fields.FindField(def_SourceTableFieldName) as TDAField) then begin
lField := aTables[i].Fields.Add();
lField.Name := def_SourceTableFieldName;
lField.DataType := datInteger;
lField.InPrimaryKey := True;
lField.ServerAutoRefresh := True;
end;
end;
aTables[i].Params.AssignParamCollection(lDataTableSchema.Params);
aTables[i].CustomAttributes.Assign(lDataTableSchema.CustomAttributes);
end;
end;
else
raise Exception.Create('Result parameter of GetSchemaCall is not properly defined as String or Binary.');
end;
finally
{ Save lookup and calced fields}
if aPreserveLookupFields then
for i := Low(aTables) to High(aTables) do
for j := 0 to (lookupfields.Count-1) do
aTables[i].Fields.Add.Assign(lookupfields[j]);
if aPreserveClientCalcFields then
for i := Low(aTables) to High(aTables) do
for j := 0 to (clientcalcfields.Count-1) do
if not Assigned(aTables[i].Fields.FindField(clientcalcfields[j].Name)) then
aTables[i].Fields.Add.Assign(clientcalcfields[j]);
{ restores the old event handler pointers }
for i := Low(aTables) to High(aTables) do begin
for j := 0 to aTables[i].Fields.Count-1 do begin
lIndex := lSavedOptions[i-Low(aTables)].FieldHandlers.IndexOf(aTables[i].Fields[j].Name);
if lIndex >= 0 then begin
lHandlers := PHandlerArray(lSavedOptions[i-Low(aTables)].FieldHandlers.Objects[lIndex]);
for k := Low(HandlersToSave) to High(HandlersToSave) do
SetMethodProp(aTables[i].Fields[j], HandlersToSave[k], lHandlers[k]);
Dispose(lHandlers);
end;
end;
lSavedOptions[i-Low(aTables)].FieldHandlers.Free();
end;
end;
finally
lResultParam := GetSchemaCall.Params.FindParam(GetSchemaCall.IncomingSchemaParameter);
if Assigned(lResultParam) then lResultParam.ClearValue;
clientcalcfields.Free;
lookupfields.Free;
for i := Low(aTables) to High(aTables) do
aTables[i].Fields.FieldEventsDisabled := false;
end;
end;
*)
procedure TDARemoteDataAdapter.FillScripts(aTables: array of TDADataTable);
var
lXml: IXMLDocument;
lScriptNode: IXMLNode;
lParam: TDARemoteRequestParam;
lResultParam: TRORequestParam;
i: integer;
begin
CheckProperties;
if GetScriptsCall.MethodName = '' then
raise Exception.Create('GetScriptsCall.MethodName must be configured to retrieve scripts.');
try
lParam := GetScriptsCall.Params.FindParam(GetScriptsCall.OutgoingTableNamesParameter);
if assigned(lParam) then FillTableNamesParam(aTables, lParam);
GetScriptsCall.Execute();
lResultParam := GetScriptsCall.Params.FindParam(GetScriptsCall.IncomingScriptParameter);
if not assigned(lResultParam) or (lResultParam.DataType <> rtString) then
raise Exception.Create('Result parameter of GetScriptsCall is not properly defined.');
if Assigned(fBeforeGetScriptsCall) then fBeforeGetScriptsCall(Self, GetScriptsCall);
GetScriptsCall.Execute();
if Assigned(fAfterGetScriptsCall) then fAfterGetScriptsCall(Self, GetScriptsCall);
lXml := NewROXmlDocument;
lXml.New;
lXml.XML := UTF8ToString(lResultParam.AsAnsiString);
for i := Low(aTables) to High(aTables) do begin
lScriptNode := lXml.DocumentNode.GetNodeByName(aTables[i].Logicalname);
if assigned(lScriptNode) then
aTables[i].ScriptCode.Text := VarToWideStr(lScriptNode.Value)
else
aTables[i].ScriptCode.Text := '';
end;
finally
lParam := GetScriptsCall.Params.FindParam(GetScriptsCall.OutgoingTableNamesParameter);
if assigned(lParam) then lParam.ClearValue;
lParam := GetScriptsCall.Params.FindParam(GetScriptsCall.IncomingScriptParameter);
if assigned(lParam) then lParam.ClearValue;
end;
end;
{$IFDEF FPC}
procedure List_Union(List1,List2: TList);
var
i: integer;
begin
if List1 = List2 then Exit;
for i := 0 to List2.Count-1 do
if List1.IndexOf(List2[i])=-1 then
List1.Add(List2[i]);
end;
{$ENDIF}
function TDARemoteDataAdapter.InternalApplyUpdates(aTables,aTablesWithDetails: array of TDADataTable): boolean;
var
i: integer;
lParam, lResultparam: TRORequestParam;
begin
result := false;
try
{ Fill Input Parameters }
lParam := UpdateDataCall.Params.FindParam(UpdateDataCall.OutgoingDeltaParameter);
if not assigned(lParam) or (lParam.DataType <> rtBinary) then
raise Exception.Create('OutgoingDeltaParameter parameter of UpdateDataCall is not properly defined.');
lParam.ClearValue();
DataStreamer.Initialize(lParam.AsBinary, aiWrite);
try
for i := Low(aTables) to High(aTables) do
aTables[i].WriteDeltaToStream(DataStreamer);
finally
DataStreamer.Finalize;
end;
{ Make call }
if DataStreamer.DeltaCount > 0 then begin
if Assigned(fBeforeUpdateDataCall) then fBeforeUpdateDataCall(Self, UpdateDataCall);
UpdateDataCall.Execute();
if Assigned(fAfterUpdateDataCall) then fAfterUpdateDataCall(Self, UpdateDataCall);
{ Get Output Parameters }
if UpdateDataCall.IncomingDeltaParameter <> '' then begin // If the result parameter isn't set, we shouldn't check for a result.
lResultParam := UpdateDataCall.Params.FindParam(UpdateDataCall.IncomingDeltaParameter);
if not assigned(lResultParam) or (lResultParam.DataType <> rtBinary) then
raise Exception.Create('IncomingDeltaParameter parameter of UpdateDataCall is not properly defined.');
// Reads the incoming delta, including the details
if assigned(lResultParam.AsBinary) and (lResultParam.AsBinary.Size > 0) then begin
DataStreamer.Initialize(lResultParam.AsBinary, aiReadFromBeginning);
try
for i := Low(aTables) to High(aTables) do
aTables[i].ReadDeltaFromStream(DataStreamer);
finally
DataStreamer.Finalize;
end;
end;
end;
end;
result := true;
finally
lResultParam := UpdateDataCall.Params.FindParam(UpdateDataCall.IncomingDeltaParameter);
if assigned(lResultParam) then lResultParam.ClearValue;
lParam := UpdateDataCall.Params.FindParam(UpdateDataCall.OutgoingDeltaParameter);
if assigned(lParam) then lParam.ClearValue;
end;
end;
constructor TDARemoteDataAdapter.Create(aOwner: TComponent);
begin
inherited;
fGetSchemaCall := TDAGetSchemaRequest.Create(self);
fGetDataCall := TDAGetDataRequest.Create(self);
fUpdateDataCall := TDAUpdateDataRequest.Create(self);
fGetScriptsCall := TDAGetScriptsRequest.Create(self);
fGetSchemaCall.Name := 'GetSchemaCall';
fGetDataCall.Name := 'GetDataCall';
fUpdateDataCall.Name := 'UpdateDataCall';
fGetScriptsCall.Name := 'GetScriptsCall';
SetupDefaultRequest;
end;
function TDARemoteDataAdapter.CreateTableRequestInfo(aTable: TDADataTable; aIncludeSchema: boolean; aDynamicWhereExpression: TDAWhereExpression = nil): TableRequestInfo;
var
lParam: DataParameter;
j: integer;
lExpression: TDAWhereExpression;
begin
if aDynamicWhereExpression <> nil then
lExpression := aDynamicWhereExpression
else
lExpression := aTable.DynamicWhere.Expression;
if lExpression <> nil then lExpression.Validate;
if DynamicSelect or (lExpression <> nil) then begin
Result := TableRequestInfoV5.Create();
if DynamicSelect then begin
TableRequestInfoV5(Result).DynamicSelectFieldNames := StringArray.Create;
For j:=0 to aTable.FieldCount-1 do
if not (aTable.Fields[j].Lookup or (aTable.Fields[j].Calculated and not aTable.Fields[j].ServerCalculated)) then
TableRequestInfoV5(Result).DynamicSelectFieldNames.Add(AnsiToUtf8(aTable.Fields[j].Name));
end;
if lExpression <> nil then
TableRequestInfoV5(Result).WhereClause:=aTable.DynamicWhere.ExpressionToXmlNode(lExpression);
end
else
Result := TableRequestInfo.Create();
Result.MaxRecords := aTable.MaxRecords;
Result.IncludeSchema := aIncludeSchema and not (soIgnoreStreamSchema in aTable.StreamingOptions);
Result.UserFilter := AnsiToUtf8(aTable.Where.Clause);
for j := 0 to aTable.Params.Count-1 do begin
lParam := Result.Parameters.Add();
lParam.Name := AnsiToUtf8(aTable.Params[j].Name);
lParam.Value := aTable.Params[j].Value;
end;
end;
destructor TDARemoteDataAdapter.Destroy;
begin
FreeAndNil(fGetSchemaCall);
FreeAndNil(fGetDataCall);
FreeAndNil(fUpdateDataCall);
FreeAndNil(fGetScriptsCall);
FreeAndNil(fSchema);
inherited;
end;
procedure TDARemoteDataAdapter.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = RemoteService) then RemoteService := nil;
end;
procedure TDARemoteDataAdapter.SetRemoteService(const Value: TRORemoteService);
begin
if Value <> fRemoteService then begin
fRemoteService := Value;
if assigned(fRemoteService) then fRemoteService.FreeNotification(self);
GetSchemaCall.RemoteService := fRemoteService;
GetDataCall.RemoteService := fRemoteService;
UpdateDataCall.RemoteService := fRemoteService;
GetScriptsCall.RemoteService := fRemoteService;
end;
end;
{ Schema }
procedure TDARemoteDataAdapter.SetCacheSchema(const Value: boolean);
begin
fCacheSchema := Value;
if not fCacheSchema then
FlushSchema();
end;
function TDARemoteDataAdapter.GetSchema: TDASchema;
begin
result := ReadSchema(not fCacheSchema);
end;
function TDARemoteDataAdapter.Get_GetDataCall: TDARemoteRequest;
begin
result := GetDataCall;
end;
function TDARemoteDataAdapter.Get_GetSchemaCall: TDARemoteRequest;
begin
result := GetSchemaCall;
end;
function TDARemoteDataAdapter.Get_GetScriptsCall: TDARemoteRequest;
begin
result := GetScriptsCall;
end;
function TDARemoteDataAdapter.Get_UpdateDataCall: TDARemoteRequest;
begin
result := UpdateDataCall;
end;
function TDARemoteDataAdapter.ReadSchema(aForceReRead: boolean): TDASchema;
var
lResultParam: TRORequestParam;
begin
CheckProperties;
lResultParam := GetSchemaCall.Params.FindParam(GetSchemaCall.IncomingSchemaParameter);
if not assigned(lResultParam) then
raise Exception.Create('Result parameter of GetSchemaCall is not defined.');
if not (lResultParam.DataType in [rtString]) then
raise Exception.Create('Result parameter of GetSchemaCall is not properly defined as String.');
if aForceReRead then
FreeAndNil(fSchema);
if not assigned(fSchema) then try
DoGetSchemaCall();
FreeAndNil(fSchema);
fSchema := TDASchema.Create(nil);
try
fSchema.LoadFromXml(Utf8ToAnsi(lResultParam.AsAnsiString));
except
fSchema.LoadFromXml(lResultParam.AsString); // try to load schema as plain text
end;
finally
if Assigned(lResultParam) then lResultParam.ClearValue;
end;
result := fSchema;
end;
procedure TDARemoteDataAdapter.FlushSchema;
begin
FreeAndNil(fSchema);
end;
procedure TDARemoteDataAdapter.SetupDefaultRequest;
begin
GetSchemaCall.SetupDefaultRequest();
GetDataCall.SetupDefaultRequest();
UpdateDataCall.SetupDefaultRequest();
GetScriptsCall.SetupDefaultRequest();
end;
procedure TDARemoteDataAdapter.SetupDefaultRequestV3;
begin
GetSchemaCall.SetupDefaultRequestV3();
GetDataCall.SetupDefaultRequestV3();
UpdateDataCall.SetupDefaultRequestV3();
GetScriptsCall.SetupDefaultRequestV3();
end;
procedure TDARemoteDataAdapter.CheckProperties;
begin
inherited;
Check(not assigned(RemoteService), Name + '.RemoteService must be assigned.');
RemoteService.CheckProperties();
end;
procedure TDARemoteDataAdapter.Loaded;
begin
inherited;
{$IFDEF DELPHI6}
// Delphi 6 doesn't call Loaded of any of the sub components.
fGetDataCall.Loaded;
fGetSchemaCall.Loaded;
fUpdateDataCall.Loaded;
fGetScriptsCall.Loaded;
{$ENDIF}
end;
function TDARemoteDataAdapter.InternalFillSchema: TRODataType;
var
lResultParam: TRORequestParam;
begin
lResultParam := GetSchemaCall.Params.FindParam(GetSchemaCall.IncomingSchemaParameter);
if not assigned(lResultParam) then
raise Exception.Create('Result parameter of GetSchemaCall is not defined.');
Result := lResultParam.DataType;
case Result of
rtBinary:begin
DoGetSchemaCall();
if not assigned(lResultParam.AsBinary) or (lResultParam.AsBinary.Size = 0 ) then
raise Exception.Create('Server returned an empty buffer for schema.');
end;
rtString: begin
Schema;
end;
end;
end;
function TDARemoteDataAdapter.GetSchemaStream: Binary;
var
lResultParam: TRORequestParam;
begin
lResultParam := GetSchemaCall.Params.FindParam(GetSchemaCall.IncomingSchemaParameter);
if not assigned(lResultParam) then
raise Exception.Create('Result parameter of GetSchemaCall is not defined.');
if not assigned(lResultParam.AsBinary) or (lResultParam.AsBinary.Size = 0 ) then
raise Exception.Create('Server returned an empty buffer for schema.');
Result := lResultParam.AsBinary;
end;
procedure TDARemoteDataAdapter.InternalFillSchema_ClearParams;
var
lResultParam: TRORequestParam;
begin
lResultParam := GetSchemaCall.Params.FindParam(GetSchemaCall.IncomingSchemaParameter);
if Assigned(lResultParam) then lResultParam.ClearValue;
end;
procedure TDARemoteDataAdapter.InternalReconcileDialog(
RemoteDataAdapter: TDABaseRemoteDataAdapter; var AFailedDeltaList: TList;
aTableList: TList);
begin
ReconcileDialog(Self,AFailedDeltaList,aTableList);
end;
end.