Componentes.Terceros.RemObj.../internal/5.0.23.613/1/Data Abstract for Delphi/Source/uDADataTable.pas

4675 lines
145 KiB
ObjectPascal

unit uDADataTable;
{----------------------------------------------------------------------------}
{ 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, DB, Contnrs, SysUtils,
{$IFDEF MSWINDOWS}ActiveX,{$ENDIF}
uRODL, uROTypes, uROClasses, uROClientIntf, uRODynamicRequest,uDAExpressionEvaluator,
uDAInterfaces, uDAClasses, uDAEngine, uDAScriptingProvider, uDADataStreamer, uDADelta,
DataAbstract3_Intf, DataAbstract4_Intf,uDAWhere;
const
RecIDFieldName = 'RecID'; // Do not change!
AllChanges = [ctInsert, ctUpdate, ctDelete];
type
//ToDo: remove and replace these three with TRO(Dynamic)Request*
TDARemoteRequest = TRODynamicRequest;
TDARemoteRequestParam = TRORequestParam;
TDARemoteRequestParams = TRORequestParamCollection;
{ Other types }
float = double;
datetime = TDateTime;
TDADataTable = class;
TDatasetClass = class of TDataset;
TDADataTableRules = class;
TDADataTableNotifyEvent = procedure(DataTable: TDADataTable) of object;
TDADataTableFilterEvent = procedure(DataTable: TDADataTable; var Accept: Boolean) of object;
TDADataTableErrorEvent = procedure(DataTable: TDADataTable; Error: EDatabaseError; var Action: TDataAction) of object;
TDADataTableDynamicMethodEvent = procedure(DataTable: TDADataTable; const aMessage: IROMessage) of object;
TDADataTableRemoteRequestEvent = procedure(DataTable: TDADataTable; Request: TDARemoteRequest) of object;
TDADataTableDataChangeEvent = procedure(DataTable: TDADataTable; Field: TDAField) of object;
TDADataRequestStreamEvent = procedure(DataTable: TDADataTable; Stream: TStream) of object;
//TDADelta = class;
TDAApplyUpdatesError = procedure(DataTable: TDADataTable; const Delta: IDADelta; var Ignore: boolean) of object;
TDAAfterApplyUpdatesEvent = procedure(DataTable: TDADataTable; const Delta: IDADelta) of object;
TDABeforeApplyUpdatesEvent = procedure(DataTable: TDADataTable; const Delta: IDADelta) of object;
TDADetailOption = (dtCascadeOpenClose,
dtCascadeApplyUpdates,
dtAutoFetch,
dtCascadeDelete,
dtCascadeUpdate,
dtDisableLogOfCascadeDeletes,
dtDisableLogOfCascadeUpdates,
dtIncludeInAllInOneFetch);
TDADetailOptions = set of TDADetailOption;
TDAMasterOption = (moCascadeOpenClose,
moCascadeApplyUpdates,
moCascadeDelete,
moCascadeUpdate,
moDisableLogOfCascadeDeletes,
moDisableLogOfCascadeUpdates,
moAllInOneFetch);
TDAMasterOptions = set of TDAMasterOption;
TDAStreamingOption = (soIgnoreStreamSchema, soDisableEventsWhileStreaming);
TDAStreamingOptions = set of TDAStreamingOption;
TDARemoteUpdatesOption = (ruoOnPost);
TDARemoteUpdatesOptions = set of TDARemoteUpdatesOption;
TDABaseRemoteDataAdapter = class(TComponent)
protected
function GetDataStreamer: TDADataStreamer; virtual; abstract;
{ backward compatibility: to provide access to these in the legacy events }
function Get_GetSchemaCall: TDARemoteRequest; virtual;
function Get_GetDataCall: TDARemoteRequest; virtual;
function Get_UpdateDataCall: TDARemoteRequest; virtual;
function Get_GetScriptsCall: TDARemoteRequest; virtual;
public
function ApplyUpdates(aTables: array of TDADataTable; aRefetchAll: boolean = false): boolean; virtual; abstract;
procedure Fill(aTables: array of TDADataTable; aSaveCursor: boolean; aIncludeSchema: boolean); overload; virtual; abstract;
procedure Fill(aTables: array of TDADataTable; aTableRequestInfoArray: array of TableRequestInfo; aSaveCursor: boolean=false;aIncludeSchema: boolean=false); overload; virtual; abstract;
procedure Fill(aTables: array of TDADataTable; aWhereClauses : array of TDAWhereExpression; aSaveCursor: boolean=false; aIncludeSchema: boolean=false); overload; virtual; abstract;
procedure FillSchema(aTables: array of TDADataTable; aPreserveLookupFields: boolean = false; areserveClientCalcFields : boolean = false); virtual; abstract;
procedure FillScripts(aTables: array of TDADataTable); virtual; abstract;
property DataStreamer: TDADataStreamer read GetDataStreamer;
end;
{ IDADataTableDataset }
IDADataTableDataset = interface
['{3BADA4F8-BA32-411C-A7CD-DEBD10A4AF06}']
function GetDataTable: TDADataTable; safecall;
end;
{ IDARangeController }
IDARangeController = interface
['{5A182854-B824-496F-80C2-6F8064003E13}']
procedure ApplyRange; safecall;
procedure CancelRange; safecall;
procedure SetRange(const StartValues, EndValues: array of const); safecall;
procedure EditRangeEnd; safecall;
procedure EditRangeStart; safecall;
procedure SetRangeEnd; safecall;
procedure SetRangeStart; safecall;
end;
{ IDANativeDatasetStreaming }
TDANativeDataFormat = (ndfBinary, ndfXML);
IDANativeDatasetStreaming = interface
['{00B37B20-23DA-49A5-BB5D-B96E50C210F4}']
procedure NativeSaveToFile(const aFileName : string; DataFormat : TDANativeDataFormat = ndfBinary);
procedure NativeLoadFromFile(const aFileName : string);
procedure NativeSaveToStream(aStream : TStream; DataFormat : TDANativeDataFormat = ndfBinary);
procedure NativeLoadFromStream(aStream : TStream);
end;
{ TDADataSource }
TDADataSource = class(TDABaseDataSource)
private
fDataTable: TDADataTable;
function GetDataset: TDataset;
procedure SetDataTable(const Value: TDADataTable);
procedure SetDataset(const Value: TDataset);
function GetOpening: boolean;
function GetActive: boolean;
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
property Dataset: TDataset read GetDataset write SetDataset; // hide base class property
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
property Opening: boolean read GetOpening;
property Active: boolean read GetActive;
published
property DataTable: TDADataTable read fDataTable write SetDataTable;
end;
{ TDADataTable }
TDASortDirection = (sdAscending, sdDescending);
TDAMasterMappingMode = (mmDataRequest, mmParams, mmWhere);
TDASortDirectionArray = array of TDASortDirection;
TStringArray = array of string;
IDADataTableScriptingProvider = interface(IDAScriptingProvider)
['{E16B7359-C733-4F09-96A8-10527CFABB6D}']
procedure RunDataTableScript(aDataTable: TDADataTable; const aScript: string; const aMethod: string; aLanguage:TROSEScriptLanguage);
end;
TAutoIncArray = array of Int64;
{$WARN SYMBOL_DEPRECATED OFF}
TDADataTable = class(TScriptableComponent, {$IFDEF MSWINDOWS}ISupportErrorInfo,{$ENDIF} IDADataTable, IDASQLCommand, IDADataset, IDAEditableDataset, IDADeltaOwner, IDADataReader, IDADatasetEx)
private
fCurrRecId: integer;
fMasterLink: TMasterDataLink;
fDelta: IDADelta;
fWhere: TDAWhere;
fRecIDField: TIntegerField;
fStreamedActive,
fRefreshing,
fOpening: boolean;
fDataset: TDataset;
fFields: TDAFieldCollection;
fAfterEdit: TDADataTableNotifyEvent;
fAfterInsert: TDADataTableNotifyEvent;
fAfterDelete: TDADataTableNotifyEvent;
fBeforeScroll: TDADataTableNotifyEvent;
fAfterClose: TDADataTableNotifyEvent;
fBeforePost: TDADataTableNotifyEvent;
fAfterScroll: TDADataTableNotifyEvent;
fBeforeCancel: TDADataTableNotifyEvent;
fBeforeRefresh: TDADataTableNotifyEvent;
fBeforeOpen: TDADataTableNotifyEvent;
fAfterRefresh: TDADataTableNotifyEvent;
fAfterOpen: TDADataTableNotifyEvent;
fBeforeEdit: TDADataTableNotifyEvent;
fBeforeClose: TDADataTableNotifyEvent;
fBeforeDelete: TDADataTableNotifyEvent;
fAfterPost: TDADataTableNotifyEvent;
fOnCalcFields: TDADataTableNotifyEvent;
fOnNewRecord: TDADataTableNotifyEvent;
fAfterCancel: TDADataTableNotifyEvent;
fBeforeInsert: TDADataTableNotifyEvent;
fOnFilterRecord: TDADataTableFilterEvent;
fOnEditError: TDADataTableErrorEvent;
fOnDeleteError: TDADataTableErrorEvent;
fOnPostError: TDADataTableErrorEvent;
fBeforeFieldChange: TDADataTableDataChangeEvent;
fAfterFieldChange: TDADataTableDataChangeEvent;
fLogChanges: boolean;
fRemoteFetchEnabled: boolean;
fSortDirections: TDASortDirectionArray;
fSortFieldNames: TStringArray;
fParams: TDAParamCollection;
fFetchedMasters: TStringList;
fMasterParamsMappings,
fMasterRequestMappings: TStringList;
fDynamicWhere: TDAWhereBuilder;
fDetailOptions: TDADetailOptions;
fMasterOptions: TDAMasterOptions;
fLogicalName: string;
fClosing: boolean;
fFetching: boolean;
fStreaming: boolean;
fOnAfterSchemaCall: TDADataTableRemoteRequestEvent;
fOnAfterDataRequestCall: TDADataTableRemoteRequestEvent;
fOnBeforeSchemaCall: TDADataTableRemoteRequestEvent;
fOnBeforeDataRequestCall: TDADataTableRemoteRequestEvent;
fOnBeforeDataUpdateCall: TDADataTableRemoteRequestEvent;
fOnAfterDataUpdateCall: TDADataTableRemoteRequestEvent;
//fOnApplyUpdatesError: TDAApplyUpdatesError;
fOnReceiveDataStream: TDADataRequestStreamEvent;
fStreamingOptions: TDAStreamingOptions;
fRemoteUpdateOptions: TDARemoteUpdatesOptions;
fLocalSchema: TDASchema;
fLocalConnection: string;
fBusinessRulesID: string;
fBusinessRules: TDADataTableRules;
fFieldRules: TObjectList;
fAutoIncs : TAutoIncArray;
fOnAfterApplyUpdates: TDADataTableNotifyEvent;
fOnBeforeApplyUpdates: TDABeforeApplyUpdatesEvent;
fMasterMappingMode: TDAMasterMappingMode;
fMaxRecords: integer;
fOnBeforeMergeDelta: TDADataTableNotifyEvent;
fOnAfterMergeDelta: TDADataTableNotifyEvent;
fStoreActive: boolean;
fScriptCode: TStrings;
fOnBeforeScriptCall: TDADataTableRemoteRequestEvent;
fOnAfterScriptCall: TDADataTableRemoteRequestEvent;
fOpenTick: cardinal;
fAfterOpenIDataset: TDAAfterOpenDatasetEvent;
fBeforeOpenIDataset: TDABeforeOpenDatasetEvent;
fRemoteDataAdapter: TDABaseRemoteDataAdapter;
fLocalDataStreamer: TDADataStreamer;
fCustomAttributes: TStrings;
fExpressionEvaluator: TDAStdExpressionEvaluator;
fHasReducedDelta: Boolean;
procedure SetLocalDataStreamer(const Value: TDADataStreamer);
procedure SetRemoteDataAdapter(const Value: TDABaseRemoteDataAdapter);
procedure SetLogChanges(const Value: boolean);
function GetDataset: TDataset; safecall;
function GetFields: TDAFieldCollection; safecall;
procedure SetFields(const Value: TDAFieldCollection);
function GetActive: boolean; safecall;
procedure SetActive(Value: boolean); safecall;
function GetLogChanges: boolean;
procedure SetParams(const Value: TDAParamCollection);
function GetEditing: boolean;
function GetMasterRequestMappings: TStrings;
procedure SetMasterRequestMappings(const Value: TStrings);
procedure TempSetRowRecIDValue(Sender: TDataset);
procedure SetLocalSchema(const Value: TDASchema);
procedure LoadFromLocalSchema;
procedure SetBusinessRulesID(const Value: string);
function GetHasDelta: boolean;
function GetHasDeltaRecursive: boolean;
function GetRecNo: integer;
procedure SetRecNo(const Value: integer);
{ published property accessors cannot be safecall, so we need wrappers: }
function GetFieldsProperty: TDAFieldCollection;
function GetActiveProperty: boolean;
procedure SetActiveProperty(const Value: boolean);
function GetParamsProperty: TDAParamCollection;
function GetMasterParamsMappings: TStrings;
procedure SetMasterParamsMappings(const Value: TStrings);
procedure PackAllInOneFetchInfoArray(aDataTable : TDADataTable; OutArray: TDADatasetRequestInfoArray);
procedure OnWhereChange(Sender: TObject);
procedure SetScriptCode(const Value: TStrings);
function GetDeltaInitialized: boolean;
procedure SetCustomAttributes(const Value: TStrings);
function Local_ApplyUpdates(RefetchAll: boolean = FALSE): boolean;
procedure InternalCancelUpdateChange(Change: TDADeltaChange);
procedure ExpessionEvaluatorGetValue(Sender: TDAExpressionEvaluator; const aIdentifier: string; out aValue: Variant);
procedure DoCascadeRemoteAllInOneFetch(aStreamer: TDADataStreamer);
protected
function CreateAutoIncArray: TAutoIncArray;
function GetAutoIncs: TAutoIncArray; virtual;
procedure SetAutoIncs(const Value: TAutoIncArray); virtual;
property AutoIncs: TAutoIncArray read GetAutoIncs write SetAutoIncs;
function GetCurrRecId: integer; virtual;
procedure SetCurrRecId(const Value: integer); virtual;
procedure Loaded; override;
// To override
function GetDatasetClass: TDatasetClass; virtual; abstract;
procedure CreateInternalFields(aDataset: TDataset; someFieldDefinitions: TDAFieldCollection); virtual;
procedure DoRefresh(aDataset: TDataset);
procedure DoSort(const FieldNames: array of string; const Directions: array of TDASortDirection); virtual; abstract;
procedure SetMasterSource(const Value: TDADataSource); virtual;
function GetMasterSource: TDADataSource; virtual; abstract;
procedure SetDetailsFields(const Value: string); virtual; abstract;
procedure SetMasterFields(const Value: string); virtual;
function GetDetailFields: string; virtual; abstract;
function GetMasterFields: string; virtual; abstract;
function GetFilter: string; virtual; abstract;
function GetFiltered: boolean; virtual; abstract;
procedure SetFilter(const Value: string); virtual; abstract;
procedure SetFiltered(const Value: boolean); virtual; abstract;
function GetReadOnly: boolean; virtual;
procedure SetReadOnly(const Value: boolean); virtual;
procedure AttachEventHooks(aDataset: TDataset); virtual;
procedure DetachEventHooks(aDataset: TDataset); virtual;
// Internal
procedure DoBeforeOpenDataset; virtual;
procedure DoBeforeCloseDataset; virtual;
procedure DoAfterOpenDataset; virtual;
procedure DoAfterCloseDataset; virtual;
procedure DoOpen(IgnoreAutoFetchSettings: Boolean = False); virtual;
// Internal TDataset event handler hooks
procedure InternalAfterInsert(Sender: TDataset); dynamic;
procedure InternalAfterEdit(Sender: TDataset); dynamic;
procedure InternalBeforePost(Sender: TDataset); dynamic;
procedure InternalBeforeCancel(Sender: TDataset); dynamic;
procedure InternalAfterDelete(Sender: TDataset); dynamic;
procedure InternalBeforeScroll(Sender: TDataset); dynamic;
procedure InternalAfterScroll(Sender: TDataset); dynamic;
procedure InternalBeforeRefresh(Sender: TDataset); dynamic;
procedure InternalAfterRefresh(Sender: TDataset); dynamic;
procedure InternalOnCalcFields(Sender: TDataset); dynamic;
procedure InternalOnNewRecord(Sender: TDataset); dynamic;
procedure InternalAfterCancel(Sender: TDataset); dynamic;
procedure InternalBeforeInsert(Sender: TDataset); dynamic;
procedure InternalBeforeDelete(Sender: TDataset); dynamic;
procedure InternalBeforeEdit(Sender: TDataset); dynamic;
procedure InternalAfterPost(Sender: TDataset); dynamic;
procedure InternalBeforeFieldUpdate(Sender: TDACustomField);
procedure InternalAfterFieldUpdate(Sender: TDACustomField);
procedure InternalOnFilterRecord(Dataset: TDataset; var Accept: Boolean); dynamic;
procedure InternalOnDeleteError(DataSet: TDataSet; Error: EDatabaseError; var Action: TDataAction); dynamic;
procedure InternalOnEditError(DataSet: TDataSet; Error: EDatabaseError; var Action: TDataAction); dynamic;
procedure InternalOnPostError(DataSet: TDataSet; Error: EDatabaseError; var Action: TDataAction); dynamic;
// IDASQLCommand
function GetParams: TDAParamCollection; safecall;
procedure RefreshParams; safecall;
function Execute: integer; safecall;
function GetText: string; safecall;
procedure SetText(const Value: string); safecall;
function GetName: string; safecall;
// IDADeltaOwner
function GetDelta: IDADelta; safecall;
// IDADataReader
function IDADataReader.First = DataReaderFirst;
function IDADataReader.Next = DataReaderNext;
function DataReaderFirst: boolean; safecall;
function DataReaderNext: boolean; safecall;
function GetFieldNames(Index: integer): string; safecall;
function GetFieldIndexes(const aName: string): integer; safecall;
function GetAsBoolean(Index: integer): boolean; overload; safecall;
function GetAsCurrency(Index: integer): currency; overload; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF}
function GetAsDateTime(Index: integer): TDateTime; overload; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF}
function GetAsFloat(Index: integer): double; overload; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF}
function GetAsInteger(Index: integer): integer; overload; safecall;
function GetAsString(Index: integer): string; overload; safecall;
function GetAsVariant(Index: integer): variant; overload; safecall;
function GetAsBoolean(const FieldName: string): boolean; overload; safecall;
function GetAsCurrency(const FieldName: string): currency; overload; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF}
function GetAsDateTime(const FieldName: string): TDateTime; overload; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF}
function GetAsFloat(const FieldName: string): double; overload; {$IFNDEF FPC_SAFECALL_BUG}safecall;{$ENDIF}
function GetAsInteger(const FieldName: string): integer; overload; safecall;
function GetAsString(const FieldName: string): string; overload; safecall;
function GetAsVariant(const FieldName: string): variant; overload; safecall;
// IDADataset
function GetIsEmpty: boolean; safecall;
function GetRecordCount: integer; safecall;
function GetFieldCount: integer; safecall;
function GetBOF: boolean; safecall;
function GetEOF: boolean; safecall;
function GetSQL: string; safecall;
procedure SetSQL(const Value: string); safecall;
function SQLContainsDynamicWhere: boolean; safecall;
function GetFieldValues(Index: integer): Variant; safecall;
function GetNames(Index: integer): string; safecall;
function GetWhere: TDAWhere; safecall; deprecated;
function GetDynamicWhere: TDAWhereBuilder; safecall;
procedure SetDynamicWhere(const Value: TDAWhereBuilder);safecall;
function GetPrepared: boolean; safecall;
procedure SetPrepared(Value: boolean); safecall;
function GetState: TDataSetState; safecall;
function GetLogicalName: string; safecall;
procedure SetLogicalName(aName : string); safecall;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure OnMasterChange(Sender: TObject); virtual;
procedure OnMasterDisable(Sender: TObject); virtual;
function GetOnAfterOpen: TDAAfterOpenDatasetEvent; safecall;
function GetOnBeforeOpen: TDABeforeOpenDatasetEvent; safecall;
procedure SetOnAfterOpen(const Value: TDAAfterOpenDatasetEvent); safecall;
procedure SetOnBeforeOpen(const Value: TDABeforeOpenDatasetEvent); safecall;
function GetOnAfterExecute: TDAAfterExecuteCommandEvent; safecall;
function GetOnBeforeExecute: TDABeforeExecuteCommandEvent; safecall;
procedure SetOnAfterExecute(const Value: TDAAfterExecuteCommandEvent); safecall;
procedure SetOnBeforeExecute(const Value: TDABeforeExecuteCommandEvent); safecall;
function GetOnExecuteError: TDAExecuteCommandErrorEvent; safecall;
procedure SetOnExecuteError(const Value: TDAExecuteCommandErrorEvent); safecall;
function GetOnOpenError: TDAOpenDatasetErrorEvent; safecall;
procedure SetOnOpenError(const Value: TDAOpenDatasetErrorEvent); safecall;
procedure NotifyFieldsClear;
// IInterface
function QueryInterface(const IID: TGUID; out Obj): HResult; override;
property MasterLink: TMasterDataLink read fMasterLink;
{$IFDEF MSWINDOWS}
protected
function InterfaceSupportsErrorInfo(const iid: TGUID): HResult; stdcall;
public
function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult; override;
{$ENDIF}
public { for Delta }
property RecIDField : TIntegerField read fRecIDField write fRecIDField;
function GetRowRecIDValue: integer;
procedure CallScript(const aEvent: string);
procedure InitializeDataTable;
procedure DoCascadeOperation(aStreamer: TDADataStreamer; aOption: TDAMasterOption);
procedure WriteDeltaToStream(aStreamer: TDADataStreamer);
procedure ReadDeltaFromStream(aStreamer: TDADataStreamer; aFailedDeltas:TList);overload;
procedure ReadDeltaFromStream(aStreamer: TDADataStreamer); overload;
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
procedure EnableConstraints; virtual; safecall; abstract;
procedure DisableConstraints; virtual; safecall; abstract;
procedure LoadFromRemoteSource(BookmarkPosition: boolean = FALSE); virtual;
procedure FetchMastersDetails(aMasterTable : TDADataTable = NIL; aRequestMappings : TStrings = NIL; IgnoreAutoFetchSettings : Boolean = False); dynamic;
procedure LoadSchema(PreserveLookupFields : boolean = FALSE; PreserveClientCalcFields : boolean = FALSE);
procedure LoadScript(aDatasetName : string = '');
function ApplyUpdates(RefetchAll: boolean = FALSE): boolean; dynamic;
procedure CancelUpdates(IncludeDetails : boolean = TRUE);
procedure CancelUpdateChange(Change: TDADeltaChange;IncludeDetails : boolean = TRUE);
procedure Sort(const FieldNames: array of string; const Directions: array of TDASortDirection);
procedure UnSort;
procedure ClearFields;
procedure ClearRows;
procedure CloneSelectedRecord(Source: TDADataTable; DoPost: boolean = TRUE); overload;
procedure CloneSelectedRecord(const Source: IDADataset; DoPost: boolean = TRUE); overload;
procedure SaveToStream(aStream: TStream);
procedure LoadFromStream(aStream: TStream);
procedure SaveToFile(const aFileName: string);
procedure LoadFromFile(const aFileName: string);
procedure MergeDelta; virtual;
// Master detail
function GetDetailDataTables: TList;
function GetDetailTablesforApplyUpdate(aRecursive: boolean = True): TList;
procedure GetDetailTablesforAllinOneFetch(aRemote, aLocal:TList; aRecursive: boolean);
function GetMasterDataTable : TDADataTable;
// Methods
procedure Open; safecall;
procedure Close; safecall;
procedure EnableControls; safecall;
procedure DisableControls; safecall;
procedure Next; safecall;
procedure Edit; safecall;
procedure Insert; safecall;
procedure Post; safecall;
procedure Cancel; safecall;
procedure Append; safecall;
procedure Delete; safecall;
procedure Prior; safecall;
procedure First; safecall;
procedure Last; safecall;
procedure Refresh; safecall;
function Locate(const KeyFields: string; const KeyValues: Variant; Options: TLocateOptions): Boolean; safecall;
function Lookup(const KeyFields: string; const KeyValues: Variant; const ResultFields: string): Variant; safecall;
function FieldByName(const aName: string): TDAField; safecall;
function FindField(const aName: string): TDAField; safecall;
function ParamByName(const aName: string): TDAParam; safecall;
function GetBookmark: pointer; safecall;
procedure GotoBookmark(Bookmark: TBookmark); safecall;
procedure FreeBookmark(Bookmark: TBookmark); safecall;
procedure EnableEventHandlers; safecall;
procedure DisableEventHandlers; safecall;
procedure InternalSetFetching(aFetching: boolean);
procedure AddRecord(const FieldNames : array of string; const FieldValues : array of Variant); safecall;
function GetCurrentRecIdValue: integer;
procedure SetCurrentRecIdValue(Value: integer);
// Properties
property CurrRecId: integer read GetCurrRecId write SetCurrRecId;
property RecIDValue: integer read GetRowRecIDValue;
property Delta: IDADelta read GetDelta write fDelta;
property RecNo : integer read GetRecNo write SetRecNo;
property BOF: boolean read GetBOF;
property EOF: boolean read GetEOF;
property RecordCount: integer read GetRecordCount;
property FieldCount: integer read GetFieldCount;
property FieldValues[Index: integer]: Variant read GetFieldValues;
property Names[Index: integer]: string read GetNames;
property SortFieldNames: TStringArray read fSortFieldNames;
property SortDirections: TDASortDirectionArray read fSortDirections;
property Opening: boolean read fOpening;
property Closing: boolean read fClosing;
property Editing: boolean read GetEditing;
property Fetching: boolean read fFetching;
property State: TDataSetState read GetState;
property Dataset: TDataset read GetDataset;
property IsEmpty : boolean read GetIsEmpty;
property BusinessEventsObj: TDADataTableRules read fBusinessRules;
property HasDelta: boolean read GetHasDelta;
property HasDeltaRecursive: boolean read GetHasDeltaRecursive;
property DeltaInitialized: boolean read GetDeltaInitialized;
property Where : TDAWhere read GetWhere;
property DynamicWhere: TDAWhereBuilder read GetDynamicWhere write SetDynamicWhere;
procedure CheckProperties(ACheckRemoteFetching: Boolean=False); virtual;
property HasReducedDelta: boolean read fHasReducedDelta;
published
property Active: boolean read GetActiveProperty write SetActiveProperty stored fStoreActive default false;
property StoreActive: boolean read fStoreActive write fStoreActive default false;
property RemoteUpdatesOptions: TDARemoteUpdatesOptions read fRemoteUpdateOptions write fRemoteUpdateOptions;
property MaxRecords : integer read fMaxRecords write fMaxRecords default -1;
property Fields: TDAFieldCollection read GetFieldsProperty write SetFields;
property Params: TDAParamCollection read GetParamsProperty write SetParams;
property MasterMappingMode : TDAMasterMappingMode read fMasterMappingMode write fMasterMappingMode default mmParams;
property MasterParamsMappings : TStrings read GetMasterParamsMappings write SetMasterParamsMappings;
property LogChanges: boolean read GetLogChanges write SetLogChanges default true;
property StreamingOptions: TDAStreamingOptions read fStreamingOptions write fStreamingOptions;
property RemoteFetchEnabled: boolean read fRemoteFetchEnabled write fRemoteFetchEnabled default true;
property ScriptCode : TStrings read fScriptCode write SetScriptCode;
property CustomAttributes : TStrings read fCustomAttributes write SetCustomAttributes;
property RemoteDataAdapter: TDABaseRemoteDataAdapter read fRemoteDataAdapter write SetRemoteDataAdapter;
property BeforeOpen: TDADataTableNotifyEvent read fBeforeOpen write fBeforeOpen;
property AfterOpen: TDADataTableNotifyEvent read fAfterOpen write fAfterOpen;
property BeforeClose: TDADataTableNotifyEvent read fBeforeClose write fBeforeClose;
property AfterClose: TDADataTableNotifyEvent read fAfterClose write fAfterClose;
property BeforeInsert: TDADataTableNotifyEvent read fBeforeInsert write fBeforeInsert;
property AfterInsert: TDADataTableNotifyEvent read fAfterInsert write fAfterInsert;
property BeforeEdit: TDADataTableNotifyEvent read fBeforeEdit write fBeforeEdit;
property AfterEdit: TDADataTableNotifyEvent read fAfterEdit write fAfterEdit;
property BeforePost: TDADataTableNotifyEvent read fBeforePost write fBeforePost;
property AfterPost: TDADataTableNotifyEvent read fAfterPost write fAfterPost;
property BeforeCancel: TDADataTableNotifyEvent read fBeforeCancel write fBeforeCancel;
property AfterCancel: TDADataTableNotifyEvent read fAfterCancel write fAfterCancel;
property BeforeDelete: TDADataTableNotifyEvent read fBeforeDelete write fBeforeDelete;
property AfterDelete: TDADataTableNotifyEvent read fAfterDelete write fAfterDelete;
property BeforeScroll: TDADataTableNotifyEvent read fBeforeScroll write fBeforeScroll;
property AfterScroll: TDADataTableNotifyEvent read fAfterScroll write fAfterScroll;
property BeforeRefresh: TDADataTableNotifyEvent read fBeforeRefresh write fBeforeRefresh;
property AfterRefresh: TDADataTableNotifyEvent read fAfterRefresh write fAfterRefresh;
property OnCalcFields: TDADataTableNotifyEvent read fOnCalcFields write fOnCalcFields;
property OnNewRecord: TDADataTableNotifyEvent read fOnNewRecord write fOnNewRecord;
property OnFilterRecord: TDADataTableFilterEvent read fOnFilterRecord write fOnFilterRecord;
property ReadOnly : boolean read GetReadOnly write SetReadOnly default False;
property OnDeleteError: TDADataTableErrorEvent read fOnDeleteError write fOnDeleteError;
property OnEditError: TDADataTableErrorEvent read fOnEditError write fOnEditError;
property OnPostError: TDADataTableErrorEvent read fOnPostError write fOnPostError;
property LocalSchema: TDASchema read fLocalSchema write SetLocalSchema;
property LocalDataStreamer: TDADataStreamer read fLocalDataStreamer write SetLocalDataStreamer;
property LocalConnection: string read fLocalConnection write fLocalConnection;
property MasterSource: TDADataSource read GetMasterSource write SetMasterSource;
property MasterFields: string read GetMasterFields write SetMasterFields;
property DetailFields: string read GetDetailFields write SetDetailsFields;
property MasterRequestMappings: TStrings read GetMasterRequestMappings write SetMasterRequestMappings;
property DetailOptions: TDADetailOptions read fDetailOptions write fDetailOptions;
property MasterOptions: TDAMasterOptions read fMasterOptions write fMasterOptions;
property Filtered: boolean read GetFiltered write SetFiltered default false;
property Filter: string read GetFilter write SetFilter;
property LogicalName: string read fLogicalName write fLogicalName;
//property OnApplyUpdatesError: TDAApplyUpdatesError read fOnApplyUpdatesError write fOnApplyUpdatesError;
property OnAfterApplyUpdates : TDADataTableNotifyEvent read fOnAfterApplyUpdates write fOnAfterApplyUpdates;
property OnBeforeApplyUpdates : TDABeforeApplyUpdatesEvent read fOnBeforeApplyUpdates write fOnBeforeApplyUpdates;
property OnBeforeMergeDelta : TDADataTableNotifyEvent read fOnBeforeMergeDelta write fOnBeforeMergeDelta;
property OnAfterMergeDelta : TDADataTableNotifyEvent read fOnAfterMergeDelta write fOnAfterMergeDelta;
property OnBeforeDataRequestCall: TDADataTableRemoteRequestEvent read fOnBeforeDataRequestCall write fOnBeforeDataRequestCall;
property OnAfterDataRequestCall: TDADataTableRemoteRequestEvent read fOnAfterDataRequestCall write fOnAfterDataRequestCall;
property OnBeforeDataUpdateCall: TDADataTableRemoteRequestEvent read fOnBeforeDataUpdateCall write fOnBeforeDataUpdateCall;
property OnAfterDataUpdateCall: TDADataTableRemoteRequestEvent read fOnAfterDataUpdateCall write fOnAfterDataUpdateCall;
property OnBeforeSchemaCall: TDADataTableRemoteRequestEvent read fOnBeforeSchemaCall write fOnBeforeSchemaCall;
property OnAfterSchemaCall: TDADataTableRemoteRequestEvent read fOnAfterSchemaCall write fOnAfterSchemaCall;
property OnBeforeScriptCall: TDADataTableRemoteRequestEvent read fOnBeforeScriptCall write fOnBeforeScriptCall;
property OnAfterScriptCall: TDADataTableRemoteRequestEvent read fOnAfterScriptCall write fOnAfterScriptCall;
property OnReceiveDataStream: TDADataRequestStreamEvent read fOnReceiveDataStream write fOnReceiveDataStream;
property OnBeforeFieldChange: TDADataTableDataChangeEvent read fBeforeFieldChange write fBeforeFieldChange;
property OnAfterFieldChange: TDADataTableDataChangeEvent read fAfterFieldChange write fAfterFieldChange;
property BusinessRulesID: string read fBusinessRulesID write SetBusinessRulesID;
end;
TDADataTableClass = class of TDADataTable;
{$WARN SYMBOL_DEPRECATED ON}
{ Exceptions }
EDABizValidationException = class(EROException);
{ TDABusinessRules }
TDABusinessRules = class(TDAEngineBaseObject)
private
protected
function _AddRef: Integer; override;
function _Release: Integer; override;
public
constructor Create; virtual;
destructor Destroy; override;
end;
IDAStronglyTypedDataTable = interface
['{4D4063AA-DFD0-4B4D-8CC2-FCE3BE1D2F87}']
procedure Open;
procedure Close;
function GetActive: boolean;
procedure SetActive(const Value: boolean);
property Active: boolean read GetActive write SetActive;
procedure Append;
procedure Cancel;
procedure Delete;
procedure Edit;
procedure First;
procedure Insert;
procedure Last;
procedure Next;
procedure Post;
procedure Prior;
function Locate(const aKeyFields: string; const aKeyValues: Variant; aOptions: TLocateOptions = []): Boolean;
function Lookup(const KeyFields: string; const KeyValues: Variant; const ResultFields: string): Variant;
function GetDataTable : TDADataTable;
function GetState : TDatasetState;
function GetIsEmpty : boolean;
function GetRecNo : integer;
procedure SetRecNo(Value : integer);
function GetMasterOptions : TDAMasterOptions;
procedure SetMasterOptions(Value : TDAMasterOptions);
function GetDetailOptions : TDADetailOptions;
procedure SetDetailOptions(Value : TDADetailOptions);
function IsFieldNull(const FieldIndexOrName : Variant) : boolean;
procedure ClearField(const FieldIndexOrName : Variant);
function GetBOF: boolean;
function GetEOF: boolean;
function GetRecordCount: integer;
property BOF: boolean read GetBOF;
property EOF: boolean read GetEOF;
property RecordCount: integer read GetRecordCount;
property RecNo : integer read GetRecNo write SetRecNo;
property MasterOptions : TDAMasterOptions read GetMasterOptions write SetMasterOptions;
property DetailOptions : TDADetailOptions read GetDetailOptions write SetDetailOptions;
property IsEmpty : boolean read GetIsEmpty;
property State : TDatasetState read GetState;
property DataTable : TDADataTable read GetDataTable;
end;
{ TDAFieldRules }
TDAFieldRules = class(TDABusinessRules)
private
fField : TDAField;
fDataTable : TDADataTable;
protected
// Misc
procedure Attach(aDataTable: TDADataTable); virtual;
procedure Detach(aDataTable: TDADataTable); virtual;
// Event handler hooks
procedure OnValidate(Sender: TDACustomField); virtual;
procedure OnChange(Sender: TDACustomField); virtual;
property DataTable : TDADataTable read fDataTable;
public
constructor Create(aField : TDAField; aDataTable : TDADataTable); reintroduce; virtual;
destructor Destroy; override;
end;
TDAFieldRulesClass = class of TDAFieldRules;
{ TDADataTableRules }
TDADataTableRules = class(TDABusinessRules, IDAStronglyTypedDataTable, IDARangeController)
private
fDataTable: TDADataTable;
fDetails : TStringList;
function GetDetails(Index: integer): TDADataTable;
function GetDetailsCount: integer;
protected
// Misc
function GetDataTable: TDADataTable;
procedure Attach(aDataTable: TDADataTable); virtual;
procedure Detach(aDataTable: TDADataTable); virtual;
procedure RefreshDetails;
function FindDetail(const aLogicalName : string) : TDADataTable;
function DetailByName(const aLogicalName : string) : TDADataTable;
// Business events
procedure BeforeOpen(Sender: TDADataTable); virtual;
procedure AfterOpen(Sender: TDADataTable); virtual;
procedure BeforeClose(Sender: TDADataTable); virtual;
procedure AfterClose(Sender: TDADataTable); virtual;
procedure BeforeInsert(Sender: TDADataTable); virtual;
procedure AfterInsert(Sender: TDADataTable); virtual;
procedure BeforeEdit(Sender: TDADataTable); virtual;
procedure AfterEdit(Sender: TDADataTable); virtual;
procedure BeforePost(Sender: TDADataTable); virtual;
procedure AfterPost(Sender: TDADataTable); virtual;
procedure BeforeCancel(Sender: TDADataTable); virtual;
procedure AfterCancel(Sender: TDADataTable); virtual;
procedure BeforeDelete(Sender: TDADataTable); virtual;
procedure AfterDelete(Sender: TDADataTable); virtual;
procedure BeforeScroll(Sender: TDADataTable); virtual;
procedure AfterScroll(Sender: TDADataTable); virtual;
procedure BeforeRefresh(Sender: TDADataTable); virtual;
procedure AfterRefresh(Sender: TDADataTable); virtual;
procedure OnCalcFields(Sender: TDADataTable); virtual;
procedure OnNewRecord(Sender: TDADataTable); virtual;
procedure OnDeleteError(DataTable: TDADataTable; Error: EDatabaseError; var Action: TDataAction); virtual;
procedure OnEditError(DataTable: TDADataTable; Error: EDatabaseError; var Action: TDataAction); virtual;
procedure OnPostError(DataTable: TDADataTable; Error: EDatabaseError; var Action: TDataAction); virtual;
procedure OnFilterRecord(DataTable: TDADataTable; var Accept : boolean); virtual;
procedure OnAfterSchemaCall(DataTable: TDADataTable; Request: TDARemoteRequest); virtual;
procedure OnAfterDataRequestCall(DataTable: TDADataTable; Request: TDARemoteRequest); virtual;
procedure OnBeforeSchemaCall(DataTable: TDADataTable; Request: TDARemoteRequest); virtual;
procedure OnBeforeDataRequestCall(DataTable: TDADataTable; Request: TDARemoteRequest); virtual;
procedure OnBeforeDataUpdateCall(DataTable: TDADataTable; Request: TDARemoteRequest); virtual;
procedure OnAfterDataUpdateCall(DataTable: TDADataTable; Request: TDARemoteRequest); virtual;
procedure OnBeforeScriptCall(DataTable: TDADataTable; Request: TDARemoteRequest); virtual;
procedure OnAfterScriptCall(DataTable: TDADataTable; Request: TDARemoteRequest); virtual;
procedure OnAfterApplyUpdates(DataTable: TDADataTable); virtual;
procedure OnBeforeMergeDelta(DataTable: TDADataTable); virtual;
procedure OnAfterMergeDelta(DataTable: TDADataTable); virtual;
procedure OnReceiveDataStream(DataTable: TDADataTable; Stream: TStream); virtual;
procedure OnBeforeApplyUpdates(DataTable: TDADataTable; const Delta: IDADelta); virtual;
procedure Open; virtual;
procedure Close; virtual;
function GetActive: boolean;
procedure SetActive(const Value: boolean);
property Active: boolean read GetActive write SetActive;
procedure Append; virtual;
procedure Cancel; virtual;
procedure Delete; virtual;
procedure Edit; virtual;
procedure First; virtual;
procedure Insert; virtual;
procedure Last; virtual;
procedure Next; virtual;
procedure Post; virtual;
procedure Prior; virtual;
function GetBOF: Boolean; virtual;
function GetEOF: Boolean; virtual;
function GetRecordCount: Integer; virtual;
function Locate(const aKeyFields: String; const aKeyValues: Variant; aOptions: TLocateOptions = []): Boolean; virtual;
function Lookup(const KeyFields: string; const KeyValues: Variant; const ResultFields: string): Variant;
function GetMasterOptions : TDAMasterOptions;
procedure SetMasterOptions(Value : TDAMasterOptions);
function GetDetailOptions : TDADetailOptions;
procedure SetDetailOptions(Value : TDADetailOptions);
function GetRecNo : integer;
procedure SetRecNo(Value : integer);
function GetIsEmpty: boolean;
function GetState: TDatasetState;
function IsFieldNull(const FieldIndexOrName : Variant) : boolean;
procedure ClearField(const FieldIndexOrName : Variant);
property DataTable: TDADataTable read GetDataTable;
property Details[Index : integer] : TDADataTable read GetDetails;
property DetailCount : integer read GetDetailsCount;
property State : TDatasetState read GetState;
property IsEmpty : boolean read GetIsEmpty;
{ IDARangeController }
procedure ApplyRange; safecall;
procedure CancelRange; safecall;
procedure SetRange(const StartValues, EndValues: array of const); safecall;
procedure EditRangeEnd; safecall;
procedure EditRangeStart; safecall;
procedure SetRangeEnd; safecall;
procedure SetRangeStart; safecall;
public
constructor Create(aDataTable: TDADataTable); reintroduce; virtual;
destructor Destroy; override;
end;
TDADataTableRulesClass = class of TDADataTableRules;
{ TDADataTableList }
TDADataTableList = class(TList)
private
function GetItems(Index: integer): TDADataTable;
function GetPendingChangeCount: integer;
protected
public
constructor Create(aOwnerComponent : TComponent);
function ScanAndAdd(aOwnerComponent : TComponent) : integer;
function Add(aDataTable : TDADataTable) : integer;
procedure Remove(aDataTable : TDADataTable);
property Items[Index : integer] : TDADataTable read GetItems; default;
property PendingChangeCount : integer read GetPendingChangeCount;
end;
// Registration routines
procedure RegisterDataTableRules(const anID: string; const aDataTableRulesClass: TDADataTableRulesClass);
function FindDataTableRules(const anID: string; out aDataTableRulesClass: TDADataTableRulesClass): boolean;
procedure RegisterFieldRules(const anID: string; const aFieldRulesClass: TDAFieldRulesClass);
function FindFieldRules(const anID: string; out aFieldRulesClass: TDAFieldRulesClass): boolean;
// Helper functions
function NewDelta(aDataTable: TDADataTable): IDADelta; overload;
function DatatableFromStream(aStream : TStream;
aDataTableClass : TDADataTableClass;
anAdapter : TDADataAdapter;
const aDatasetName : string = '') : TDADataTable;
implementation
uses
{$IFDEF DESIGNTIME}
{$IFDEF MSWINDOWS}
Dialogs,
{$ENDIF MSWINDOWS}
{$IFDEF LINUX}
QDialogs,
{$ENDIF LINUX}
{$ENDIF DESIGNTIME}
TypInfo, Variants,
uROClient, uROSessions, uROXMLIntf,
uDARegExpr, uDABusinessProcessor,
uDARemoteDataAdapter;
var
_bizfields,
_bizdatatables: TStringList;
type
TDataSetHack = class(TDataSet);
function NewDelta(aDataTable: TDADataTable): IDADelta;
begin
result := TDADelta.Create(aDataTable);
end;
procedure RegisterDataTableRules(const anID: string; const aDataTableRulesClass: TDADataTableRulesClass);
var
idx: integer;
begin
idx := _bizdatatables.IndexOf(anID);
if (idx >= 0) then
_bizdatatables.Objects[idx] := TObject(aDataTableRulesClass)
else
_bizdatatables.AddObject(anID, TObject(aDataTableRulesClass));
end;
function FindDataTableRules(const anID: string; out aDataTableRulesClass: TDADataTableRulesClass): boolean;
var
idx: integer;
begin
result := FALSE;
idx := _bizdatatables.IndexOf(anID);
if (idx >= 0) then begin
aDataTableRulesClass := TDADataTableRulesClass(_bizdatatables.Objects[idx]);
result := TRUE;
end
else
aDataTableRulesClass := nil;
end;
procedure RegisterFieldRules(const anID: string; const aFieldRulesClass: TDAFieldRulesClass);
var
idx: integer;
begin
idx := _bizfields.IndexOf(anID);
if (idx >= 0) then
_bizfields.Objects[idx] := TObject(aFieldRulesClass)
else
_bizfields.AddObject(anID, TObject(aFieldRulesClass));
end;
function FindFieldRules(const anID: string; out aFieldRulesClass: TDAFieldRulesClass): boolean;
var
idx: integer;
begin
result := FALSE;
idx := _bizfields.IndexOf(anID);
if (idx >= 0) then begin
aFieldRulesClass := TDAFieldRulesClass(_bizfields.Objects[idx]);
result := TRUE;
end
else
aFieldRulesClass := nil;
end;
function DatatableFromStream(aStream : TStream;
aDataTableClass : TDADataTableClass;
anAdapter : TDADataAdapter;
const aDatasetName : string = '') : TDADataTable;
begin
result := aDataTableClass.Create(NIL);
result.RemoteFetchEnabled := FALSE;
anAdapter.ReadDataset(aStream, result, TRUE, aDatasetName);
result.First;
end;
{ TDADataTable }
constructor TDADataTable.Create(aOwner: TComponent);
begin
inherited;
fHasReducedDelta := False;
fScriptCode := TStringList.Create;
fCustomAttributes := TStringList.Create;
fMaxRecords := -1;
fMasterMappingMode := mmParams;
fMasterParamsMappings := TStringList.Create;
fFieldRules := TObjectList.Create;
fRemoteUpdateOptions := [];
fStreamingOptions := [soDisableEventsWhileStreaming];
fDetailOptions := [dtCascadeOpenClose,
dtCascadeApplyUpdates,
dtAutoFetch,
dtCascadeDelete,
dtCascadeUpdate,
dtDisableLogOfCascadeDeletes,
dtDisableLogOfCascadeUpdates,
dtIncludeInAllInOneFetch // Done to avoid breaking existing apps
];
fMasterOptions := [moCascadeOpenClose,
moCascadeApplyUpdates,
moCascadeDelete,
moCascadeUpdate,
moDisableLogOfCascadeDeletes,
moDisableLogOfCascadeUpdates];
fFetchedMasters := TStringList.Create;
fFetchedMasters.Duplicates := dupError;
fFetchedMasters.Sorted := TRUE;
fMasterRequestMappings := TStringList.Create;
fRemoteFetchEnabled := TRUE;
fStreaming := False;
SetLength(fSortDirections, 0);
SetLength(fSortFieldNames, 0);
fFields := TDAFieldCollection.Create(Self);
fFields.OnFieldBeforeUpdate := InternalBeforeFieldUpdate;
fFields.OnFieldAfterUpdate := InternalAfterFieldUpdate;
fParams := TDAParamCollection.Create(Self);
fWhere := TDAWhere.Create(fFields, TRUE);
fWhere.OnChange := OnWhereChange;
fDataset := GetDatasetClass.Create(Self);
fDataset.Name := 'Dataset';
fMasterLink := TMasterDataLink.Create(fDataset);
fMasterLink.OnMasterChange := OnMasterChange;
fMasterLink.OnMasterDisable := OnMasterDisable;
fExpressionEvaluator := TDAStdExpressionEvaluator.Create;
fExpressionEvaluator.OnGetValue := ExpessionEvaluatorGetValue;
fDynamicWhere := TDAWhereBuilder.Create;
fLogChanges := TRUE;
end;
destructor TDADataTable.Destroy;
begin
fDynamicWhere.Free;
fExpressionEvaluator.Free;
fFields.Free;
fWhere.Free;
fMasterLink.Free;
fMasterRequestMappings.Free;
fMasterParamsMappings.Free;
fFetchedMasters.Free;
if (fBusinessRules <> nil) then begin
fBusinessRules.Detach(Self);
fBusinessRules.Free;
end;
fFieldRules.Free;
fParams.Free;
fDelta := NIL;
fScriptCode.Free;
fCustomAttributes.Free;
inherited;
end;
procedure TDADataTable.OnWhereChange(Sender : TObject);
var
par : TRORequestParam;
begin
//TODO: par := DataRequestCall.FindParam(par_UserFilter);
//if (par<>NIL) then par.AsString := fWhere.Clause;
if RemoteFetchEnabled and (RemoteDataAdapter <> nil) then
begin
par := (TDARemoteDataAdapter(RemoteDataAdapter).GetDataCall).FindParam('UserFilter');
if (par <> NIL) then
par.AsString := fWhere.Clause;
end;
end;
procedure TDADataTable.AttachEventHooks(aDataset: TDataset);
var i : integer;
lFieldRulesClass : TDAFieldRulesClass;
lFieldRules : TDAFieldRules;
lField : TDAField;
begin
if (csDesigning in ComponentState) then Exit;
aDataset.BeforeInsert := InternalBeforeInsert;
aDataset.AfterInsert := InternalAfterInsert;
aDataset.BeforeEdit := InternalBeforeEdit;
aDataset.AfterEdit := InternalAfterEdit;
aDataset.BeforePost := InternalBeforePost;
aDataset.AfterPost := InternalAfterPost;
aDataset.BeforeCancel := InternalBeforeCancel;
aDataset.AfterCancel := InternalAfterCancel;
aDataset.BeforeDelete := InternalBeforeDelete;
aDataset.AfterDelete := InternalAfterDelete;
aDataset.BeforeScroll := InternalBeforeScroll;
aDataset.AfterScroll := InternalAfterScroll;
aDataset.BeforeRefresh := InternalBeforeRefresh;
aDataset.AfterRefresh := InternalAfterRefresh;
aDataset.OnCalcFields := InternalOnCalcFields;
aDataset.OnNewRecord := InternalOnNewRecord;
aDataset.OnFilterRecord := InternalOnFilterRecord;
aDataset.OnDeleteError := InternalOnDeleteError;
aDataset.OnEditError := InternalOnEditError;
aDataset.OnPostError := InternalOnPostError;
for i := 0 to (fFields.Count-1) do begin
lField := Fields[i];
if (lField.BusinessClassID='') then Continue;
Check(not FindFieldRules(lField.BusinessClassID, lFieldRulesClass), 'Invalid BusinessClassID "%s"', [lField.BusinessClassID]);
lFieldRules := lFieldRulesClass.Create(lField, Self);
fFieldRules.Add(lFieldRules);
end;
fFields.FieldEventsDisabled := FALSE;
end;
procedure TDADataTable.DetachEventHooks(aDataset: TDataset);
begin
if (csDesigning in ComponentState) then Exit;
aDataset.BeforeInsert := nil;
aDataset.AfterInsert := nil;
aDataset.BeforeEdit := nil;
aDataset.AfterEdit := nil;
aDataset.BeforePost := TempSetRowRecIDValue; // We still need to autoinc the RecID!!!
aDataset.AfterPost := nil;
aDataset.BeforeCancel := nil;
aDataset.AfterCancel := nil;
aDataset.BeforeDelete := nil;
aDataset.AfterDelete := nil;
aDataset.BeforeScroll := nil;
aDataset.AfterScroll := nil;
aDataset.BeforeRefresh := nil;
aDataset.AfterRefresh := nil;
if not Filtered then
aDataset.OnCalcFields := nil;
aDataset.OnNewRecord := nil;
aDataset.OnFilterRecord := nil;
aDataset.OnDeleteError := nil;
aDataset.OnEditError := nil;
aDataset.OnPostError := nil;
fFields.FieldEventsDisabled := TRUE;
fFieldRules.Clear; // Destroyes them
end;
procedure TDADataTable.InternalAfterDelete(Sender: TDataset);
begin
CallScript('AfterDelete');
if Assigned(AfterDelete) then AfterDelete(Self);
if Assigned(fBusinessRules) then fBusinessRules.AfterDelete(Self);
if (ruoOnPost in RemoteUpdatesOptions) then ApplyUpdates();
end;
procedure TDADataTable.InternalAfterEdit(Sender: TDataset);
begin
CallScript('AfterEdit');
if Assigned(AfterEdit) then AfterEdit(Self);
if Assigned(fBusinessRules) then fBusinessRules.AfterEdit(Self);
end;
procedure TDADataTable.InternalAfterInsert(Sender: TDataset);
var
i: integer;
begin
CallScript('AfterInsert');
if (State <> dsEdit) then begin // Somehow it's gets in dsBrowse here...
// (autoinc)
for i := 0 to (fFields.Count-1) do
if (fFields[i].DataType=datLargeAutoInc) then begin
fFields[i].AsLargeInt := AutoIncs[i];
AutoIncs[i] := AutoIncs[i]-1;
end else
if (fFields[i].DataType=datAutoInc) then begin
fFields[i].AsInteger := AutoIncs[i];
AutoIncs[i] := AutoIncs[i]-1;
end;
end;
if Assigned(AfterInsert) then AfterInsert(Self);
if Assigned(fBusinessRules) then fBusinessRules.AfterInsert(Self);
end;
procedure TDADataTable.InternalAfterRefresh(Sender: TDataset);
begin
CallScript('AfterRefresh');
if Assigned(AfterRefresh) then AfterRefresh(Self);
if Assigned(fBusinessRules) then fBusinessRules.AfterRefresh(Self);
end;
procedure TDADataTable.InternalAfterScroll(Sender: TDataset);
begin
if fStreaming and (soDisableEventsWhileStreaming in fStreamingOptions)
then Exit;
CallScript('AfterScroll');
if Assigned(AfterScroll) then AfterScroll(Self);
if Assigned(fBusinessRules) then fBusinessRules.AfterScroll(Self);
end;
procedure TDADataTable.InternalBeforeCancel(Sender: TDataset);
begin
CallScript('BeforeCancel');
if Assigned(BeforeCancel) then BeforeCancel(Self);
if Assigned(fBusinessRules) then fBusinessRules.BeforeCancel(Self);
end;
procedure TDADataTable.InternalBeforeRefresh(Sender: TDataset);
begin
CallScript('BeforeRefresh');
if Assigned(BeforeRefresh) then BeforeRefresh(Self);
if Assigned(fBusinessRules) then fBusinessRules.BeforeRefresh(Self);
DoRefresh(fDataset);
end;
procedure TDADataTable.InternalBeforeScroll(Sender: TDataset);
begin
if fStreaming and (soDisableEventsWhileStreaming in fStreamingOptions)
then Exit;
CallScript('BeforeScroll');
if Assigned(BeforeScroll) then BeforeScroll(Self);
if Assigned(fBusinessRules) then fBusinessRules.BeforeScroll(Self);
end;
procedure TDADataTable.InternalOnCalcFields(Sender: TDataset);
var
i: integer;
begin
CallScript('OnCalcFields');
if Assigned(OnCalcFields) then OnCalcFields(Self);
if Assigned(fBusinessRules) then fBusinessRules.OnCalcFields(Self);
For i:= 0 to fFields.Count-1 do
With fFields[i] do
if Calculated and (Expression <> '') then Value:= fExpressionEvaluator.Evaluate(Expression);
end;
procedure TDADataTable.InternalOnDeleteError(DataSet: TDataSet; Error: EDatabaseError; var Action: TDataAction);
begin
if Assigned(OnDeleteError) then OnDeleteError(Self, Error, Action);
if Assigned(fBusinessRules) then fBusinessRules.OnDeleteError(Self, Error, Action);
end;
procedure TDADataTable.InternalOnEditError(DataSet: TDataSet; Error: EDatabaseError; var Action: TDataAction);
begin
if Assigned(OnEditError) then OnEditError(Self, Error, Action);
if Assigned(fBusinessRules) then fBusinessRules.OnEditError(Self, Error, Action);
end;
procedure TDADataTable.InternalOnFilterRecord(Dataset: TDataset; var Accept: Boolean);
begin
if Assigned(OnFilterRecord) then OnFilterRecord(Self, Accept);
if Assigned(fBusinessRules) then fBusinessRules.OnFilterRecord(Self, Accept);
end;
procedure TDADataTable.InternalOnPostError(DataSet: TDataSet; Error: EDatabaseError; var Action: TDataAction);
begin
fDelta.RestoreLastChange; // ALEF: added as follow up to the Post errors (Jeff B.)
if Assigned(OnPostError) then OnPostError(Self, Error, Action);
if Assigned(fBusinessRules) then fBusinessRules.OnPostError(Self, Error, Action);
end;
procedure TDADataTable.SetLogChanges(const Value: boolean);
begin
fLogChanges := Value;
end;
function TDADataTable.GetDataset: TDataset;
begin
result := fDataset // inherited Dataset;
end;
function TDADataTable.GetFields: TDAFieldCollection;
begin
result := fFields;
end;
procedure TDADataTable.SetFields(const Value: TDAFieldCollection);
begin
if Active then Close;
fFields.Assign(Value);
end;
function TDADataTable.GetActive: boolean;
begin
result := fDataset.Active;
end;
procedure TDADataTable.SetActive(Value: boolean);
begin
if (csLoading in ComponentState) then
fStreamedActive := Value
else begin
if (Value <> Active) then begin
if Value then
Open
else
Close
end;
end;
end;
procedure TDADataTable.InternalOnNewRecord(Sender: TDataset);
var
i: integer;
begin
fFields.FieldEventsDisabled := TRUE;
try
try
for i := 0 to (fFields.Count - 1) do
if (fFields[i].DefaultValue <> '') then fFields[i].Value := fFields[i].DefaultValue;
fFields.FieldEventsDisabled := FALSE;
CallScript('OnNewRecord');
if Assigned(OnNewRecord) then OnNewRecord(Self);
if Assigned(fBusinessRules) then fBusinessRules.OnNewRecord(Self);
except
fDelta.CancelChange; // OnNewRecord's exception put the dataset in read mode so we must cancel the change
raise;
end;
finally
fFields.FieldEventsDisabled := FALSE; // Just in case...
end;
end;
procedure TDADataTable.DoCascadeOperation(aStreamer: TDADataStreamer; aOption: TDAMasterOption);
var
i: integer;
details: TList;
dt: TDADataTable;
flag: boolean;
lRemoteList,lLocalList: TList;
begin
if aOption = moAllInOneFetch then begin
DoCascadeRemoteAllInOneFetch(aStreamer);
exit;
end;
lRemoteList:= TList.Create;
lLocalList:= TList.Create;
GetDetailTablesforAllinOneFetch(lRemoteList,lLocalList, False);
details := GetDetailDataTables;
try
for i := 0 to (details.Count - 1) do begin
dt := TDADataTable(details[i]);
flag := dt.LogChanges;
case aOption of
moCascadeDelete: begin
if (dtDisableLogOfCascadeDeletes in dt.DetailOptions) then dt.LogChanges := FALSE;
dt.ClearRows;
end;
moCascadeOpenClose: begin
if (dtCascadeOpenClose in dt.DetailOptions) then begin
if Opening then begin
if (lLocalList.IndexOf(dt)=-1)and (lRemoteList.IndexOf(dt)=-1) then begin
dt.Close;
dt.DoOpen;
end;
end
else if Closing then
dt.Close;
end;
end;
moCascadeUpdate: begin
end;
moAllInOneFetch: begin
{
if (dtIncludeInAllInOneFetch in dt.DetailOptions) then try
dt.LogChanges := FALSE;
if Opening and not (soIgnoreStreamSchema in fStreamingOptions) then
begin
aStreamer.ReadDataset(dt.LogicalName, dt, TRUE, FALSE);
dt.InitializeDataTable;
end;
aStreamer.ReadDataset(dt.LogicalName, dt);
dt.DoCascadeOperation(aStreamer, moAllInOneFetch);
finally
dt.LogChanges := flag;
end; }
end;
end;
dt.LogChanges := flag;
end;
finally
details.Free;
lRemoteList.Free;
lLocalList.Free;
end;
end;
procedure TDADataTable.DoCascadeRemoteAllInOneFetch(aStreamer: TDADataStreamer);
var
lFetchedMasters: TStringList;
procedure ProcessDetailTable(aTable: TDADataTable);
begin
with aTable do begin
fFetchedMasters.Sorted:=False;
fFetchedMasters.AddStrings(lFetchedMasters);
fFetchedMasters.Sorted:=True;
DoCascadeRemoteAllInOneFetch(aStreamer);
end;
end;
var
lLocalList, lRemoteList: TList;
ltbl: TDADataTable;
i: integer;
lflag: boolean;
begin
if moAllInOneFetch in fMasterOptions then begin
lRemoteList:= TList.Create;
lLocalList:= TList.Create;
try
GetDetailTablesforAllinOneFetch(lRemoteList,lLocalList, False);
if (lRemoteList.Count > 0) or (lLocalList.Count > 0) then begin
lFetchedMasters:= TStringList.Create;
try
First;
while not EOF do begin
lFetchedMasters.Add(IntToStr(GetRowRecIDValue));
Next;
end;
lFetchedMasters.Sort;
// these tables are read in RDA
for i := 0 to lRemoteList.Count - 1 do begin
ProcessDetailTable(TDADataTable(lRemoteList[i]));
end;
// these tables we should read manually from streamer
for i := 0 to lLocalList.Count - 1 do begin
ltbl:= TDADataTable(lLocalList[i]);
if aStreamer.FindDatasetIndex(ltbl.LogicalName) = -1 then Continue; // may be to better raise an exception!
lflag := ltbl.LogChanges;
try
ltbl.LogChanges := False;
if Opening and not (soIgnoreStreamSchema in fStreamingOptions) then begin
aStreamer.ReadDataset(ltbl.LogicalName, ltbl, TRUE, FALSE);
ltbl.InitializeDataTable;
end;
aStreamer.ReadDataset(ltbl.LogicalName, ltbl);
finally
ltbl.LogChanges := lflag;
end;
ProcessDetailTable(ltbl);
end;
finally
lFetchedMasters.Free;
end;
end;
finally
lRemoteList.Free;
lLocalList.Free;
end;
end;
end;
procedure TDADataTable.TempSetRowRecIDValue(Sender: TDataset);
begin
if (State <> dsEdit) then begin // Somehow it's gets in dsBrowse here...
fRecIDField.AsInteger := CurrRecId;
CurrRecId := CurrRecId + 1;
end;
end;
procedure TDADataTable.CreateInternalFields(aDataset: TDataset; someFieldDefinitions: TDAFieldCollection);
var
i, cnt: integer;
fld: TFieldDef;
fldcls: TFieldClass;
realfld: TField;
begin
// Creates the RecID field
fld := aDataset.FieldDefs.AddFieldDef;
fld.DataType := ftInteger;
fld.Name := RecIDFieldName;
// Creates the autoinc map (autoinc)
AutoIncs := CreateAutoIncArray;
// Adds the data fields (non calculated) to the FieldDefs
for i := 0 to (Fields.Count - 1) do begin
if Fields[i].Calculated or Fields[i].Lookup then Continue; // Added as fields later
fld := aDataset.FieldDefs.AddFieldDef;
// (autoinc)
if (Fields[i].DataType=datLargeAutoInc)
then fld.DataType := ftLargeint
else
if (Fields[i].DataType=datAutoInc)
then fld.DataType := ftInteger
else fld.DataType := DATypeToVCLType(Fields[i].DataType);
fld.Name := Fields[i].Name;
{if not (fld.DataType in [ftFloat, ftCurrency, ftBlob, ftInteger])
then fld.Size := Fields[i].Size;}
if (fld.DataType = ftString) or (fld.DataType = ftWideString) then fld.Size := Fields[i].Size;
if (fld.DataType = ftGuid) then fld.Size := 38;
if (fld.DataType = ftFMTBcd) then begin
fld.Size:=Fields[i].DecimalScale;
fld.Precision:=Fields[i].DecimalPrecision;
end;
fld.Required := Fields[i].Required;
end;
// Creates the data fields
for i := 0 to (aDataset.FieldDefs.Count - 1) do begin
realfld := aDataset.FieldDefs[i].CreateField(aDataset);
realfld.DataSet := aDataset; // NEW
end;
// Creates the calculated fields
for i := 0 to (Fields.Count - 1) do begin
if not Fields[i].Calculated then Continue;
fldcls := DefaultFieldClasses[DATypeToVCLType(Fields[i].DataType)];
if fldcls = nil then fldcls := TStringField;
realfld := fldcls.Create(Self);
realfld.Name := aDataset.Name + Fields[i].Name;
realfld.FieldName := Fields[i].Name;
realfld.DataSet := aDataset;
if (Fields[i].DataType = datString) or (Fields[i].DataType = datWideString) then realfld.Size := Fields[i].Size;
realfld.Required := Fields[i].Required;
if Fields[i].Calculated then realfld.FieldKind := fkCalculated;
realfld.DataSet := aDataset;
end;
// Creates the lookup fields
for i := 0 to (Fields.Count - 1) do begin
if not Fields[i].Lookup then Continue;
fldcls := DefaultFieldClasses[DATypeToVCLType(Fields[i].DataType)];
if not Assigned(fldcls) then
RaiseError('No or invalid DataType specified for lookup field %s.%s',[self.Name, Fields[i].Name]);
realfld := fldcls.Create(Self);
realfld.Name := aDataset.Name + Fields[i].Name;
realfld.FieldName := Fields[i].Name;
realfld.DataSet := aDataset; // NEW
// Sets lookup properties
with Fields[i] do begin
{$IFDEF FPC}
realfld.FieldKind:=fkLookup;
{$ELSE}
realfld.Lookup := TRUE;
{$ENDIF}
if (LookupSource<>NIL) then
with TDADataSource(LookupSource) do
if Assigned(DataTable)
then realfld.LookupDataSet := DataTable.Dataset;
realfld.LookupKeyFields := LookupKeyFields;
realfld.LookupCache := LookupCache;
realfld.LookupResultField := LookupResultField;
realfld.KeyFields := KeyFields;
end;
if (Fields[i].DataType = datString) or (Fields[i].DataType = datWideString) then realfld.Size := Fields[i].Size;
//realfld.DataSet := aDataset;
end;
// Adjusts field positions (less intrusive than changing the code above)
cnt := Fields.Count-1;
for i := 0 to cnt do
aDataSet.FieldByName(Fields[i].Name).Index := i+1;
end;
procedure TDADataTable.Loaded;
begin
inherited;
if Assigned(fBusinessRules)
then fBusinessRules.Attach(Self);
Active := fStreamedActive;
AttachEventHooks(fDataset);
end;
procedure TDADataTable.DoRefresh(aDataset: TDataset);
begin
if fRefreshing then Exit;
fRefreshing := TRUE;
try
Close;
Open;
finally
fRefreshing := FALSE;
end;
end;
procedure TDADataTable.InternalBeforeInsert(Sender: TDataset);
begin
CallScript('BeforeInsert');
if Assigned(BeforeInsert) then BeforeInsert(Self);
if Assigned(fBusinessRules) then fBusinessRules.BeforeInsert(Self);
if not LogChanges or (csDesigning in ComponentState) then Exit;
fDelta.StartChange(ctInsert);
end;
procedure TDADataTable.InternalBeforeDelete(Sender: TDataset);
begin
CallScript('BeforeDelete');
if Assigned(BeforeDelete) then BeforeDelete(Self);
if Assigned(fBusinessRules) then fBusinessRules.BeforeDelete(Self);
if not LogChanges or (csDesigning in ComponentState) then Exit;
// Deletes the records from the detail tables
if (moCascadeDelete in MasterOptions) then DoCascadeOperation(nil, moCascadeDelete);
// Logs the delete
fDelta.StartChange(ctDelete);
fDelta.EndChange;
end;
procedure TDADataTable.InternalBeforeEdit(Sender: TDataset);
begin
CallScript('BeforeEdit');
if Assigned(BeforeEdit) then BeforeEdit(Self);
if Assigned(fBusinessRules) then fBusinessRules.BeforeEdit(Self);
if not LogChanges or (csDesigning in ComponentState) then Exit;
fDelta.StartChange(ctUpdate);
end;
procedure TDADataTable.InternalBeforePost(Sender: TDataset);
var details : TList;
key : string;
i : integer;
begin
CallScript('BeforePost');
if Assigned(BeforePost) then BeforePost(Self);
if Assigned(fBusinessRules) then fBusinessRules.BeforePost(Self);
for i := 0 to (fFields.Count - 1) do
if (fFields[i].RegExpression <> '') and not fFields[i].IsNull then begin
if not ExecRegExpr(fFields[i].RegExpression, fFields[i].AsString) then RaiseError('Invalid input value for field ' + fFields[i].Name);
end;
if (State <> dsEdit) then begin // Somehow it's gets in dsBrowse here...
fRecIDField.AsInteger := CurrRecId;
CurrRecId := CurrRecId + 1;
end;
// This was originally in AfterPost. Moved here because after a post filters might step in and the current
// record can change resulting in half change from record X and the remaining from record Y
if not LogChanges or (csDesigning in ComponentState) then Exit;
fDelta.EndChange;
// Adds a reference to the RecID of this record to avoid double fetching records
// This is a new master record, so it means there are no details to fetch remotely
if (State=dsInsert) then begin
key := IntToStr(GetRowRecIDValue);
details := GetDetailDataTables;
try
for i := 0 to (details.Count-1) do begin
with TDADataTable(details[i]) do
if Active and (fFetchedMasters.IndexOf(key)<0) then fFetchedMasters.Add(key);
end;
finally
details.Free;
end;
end;
if (ruoOnPost in RemoteUpdatesOptions) then try
ApplyUpdates();
except
on E: Exception do
begin
fDelta.RestoreLastChange;
raise;
end;
end;
end;
procedure TDADataTable.InternalAfterPost(Sender: TDataset);
begin
CallScript('AfterPost');
if Assigned(AfterPost) then AfterPost(Self);
if Assigned(fBusinessRules) then fBusinessRules.AfterPost(Self);
if not LogChanges or (csDesigning in ComponentState) then Exit;
end;
procedure TDADataTable.InternalAfterCancel(Sender: TDataset);
begin
CallScript('AfterCancel');
if Assigned(AfterCancel) then AfterCancel(Self);
if Assigned(fBusinessRules) then fBusinessRules.AfterCancel(Self);
fDelta.CancelChange;
end;
function TDADataTable.GetLogChanges: boolean;
begin
result := fLogChanges;
end;
procedure TDADataTable.DisableControls;
begin
fDataset.DisableControls;
end;
procedure TDADataTable.EnableControls;
begin
fDataset.EnableControls;
end;
function TDADataTable.GetBOF: boolean;
begin
result := fDataset.BOF
end;
function TDADataTable.GetEOF: boolean;
begin
result := fDataset.EOF
end;
function TDADataTable.GetFieldCount: integer;
begin
result := fFields.Count
end;
function TDADataTable.GetFieldValues(Index: integer): Variant;
begin
result := Fields[Index].Value
end;
function TDADataTable.GetNames(Index: integer): string;
begin
result := Fields[Index].Name
end;
function TDADataTable.GetRecordCount: integer;
begin
result := fDataset.RecordCount;
end;
function TDADataTable.GetSQL: string;
begin
// Not implemented in DataTables
result := '';
end;
function TDADataTable.Locate(const KeyFields: string;
const KeyValues: Variant; Options: TLocateOptions): Boolean;
begin
if VarIsArray(KeyValues) and (VarArrayHighBound(KeyValues, 1) = 0)
then result := fDataset.Locate(KeyFields, KeyValues[0], Options)
else result := fDataset.Locate(KeyFields, KeyValues, Options);
end;
procedure TDADataTable.Next;
begin
fDataset.Next;
end;
procedure TDADataTable.SetSQL(const Value: string);
begin
// Not implemented in DataTables
end;
function TDADataTable.Execute: integer;
begin
// Not implemented in DataTables
result := -1;
end;
function TDADataTable.GetParams: TDAParamCollection;
begin
// Not implemented in DataTables
result := fParams;
end;
procedure TDADataTable.RefreshParams;
begin
// Not implemented in DataTables
end;
procedure TDADataTable.Append;
begin
fDataset.Append;
end;
procedure TDADataTable.Delete;
begin
fDataset.Delete;
end;
procedure TDADataTable.Cancel;
begin
fDataset.Cancel;
end;
procedure TDADataTable.Edit;
begin
fDataset.Edit;
end;
procedure TDADataTable.Insert;
begin
fDataset.Insert;
end;
procedure TDADataTable.Post;
begin
fDataset.Post;
end;
{$WARN SYMBOL_DEPRECATED OFF}
function TDADataTable.GetWhere: TDAWhere;
begin
result := fWhere
end;
{$WARN SYMBOL_DEPRECATED ON}
procedure TDADataTable.SetRemoteDataAdapter(const Value: TDABaseRemoteDataAdapter);
begin
if Value <> fRemoteDataAdapter then begin
fRemoteDataAdapter := Value;
if assigned(fRemoteDataAdapter) then fRemoteDataAdapter.FreeNotification(self);
end;
end;
procedure TDADataTable.Close;
begin
if not Active then Exit;
fClosing := TRUE;
try
DoBeforeCloseDataset;
if Assigned(BeforeClose) then BeforeClose(Self);
if Assigned(fBusinessRules) then fBusinessRules.BeforeClose(Self);
if (moCascadeOpenClose in MasterOptions) then DoCascadeOperation(nil, moCascadeOpenClose);
Dataset.Close;
fFields.Unbind;
//Dataset.Fields.Clear;
fDelta := nil;
fFetchedMasters.Clear;
DoAfterCloseDataset;
if Assigned(AfterClose) then AfterClose(Self);
if Assigned(fBusinessRules) then fBusinessRules.AfterClose(Self);
finally
fClosing := FALSE;
end;
end;
procedure TDADataTable.InitializeDataTable;
begin
fCurrRecId := 1;
try
fDataset.Fields.Clear;
fDataset.FieldDefs.Clear;
finally
NotifyFieldsClear;
end;
try
// Creates the fields for the internal dataset
CreateInternalFields(fDataset, Fields);
finally
NotifyFieldsClear;
end;
fRecIDField := fDataset.FieldByName(RecIDFieldName) as TIntegerField;
fRecIDField.Visible := FALSE;
fFields.Bind(fDataset);
// Prepares the delta
fDelta := TDADelta.Create(Self);
(*
// Finishes to prepare the internal dataset (descendant might need additional customization and might not be open)
if RemoteFetchEnabled and
(RemoteDataAdapter<>nil) and
(TDARemoteDataAdapter(RemoteDataAdapter).GetDataCall.Default) then
LoadScript();
*)
DoBeforeOpenDataset;
if not Dataset.Active then Dataset.Open;
DoAfterOpenDataset;
end;
procedure TDADataTable.LoadFromLocalSchema;
var
lConnection: IDAConnection;
data: TStream;
gofirst, oldlog: boolean;
ds: IDADataset;
i: integer;
lDynFields: array of string;
begin
if (LocalSchema = nil) or (LogicalName = '') then begin
InitializeDataTable;
Exit;
end;
// Local but from schema. Client/Server mode
CheckProperties;
lConnection := LocalSchema.ConnectionManager.NewConnection(fLocalConnection);
try
SetLength(lDynFields, 0);
ds := LocalSchema.NewDataset(lConnection, fLogicalName,lDynFields,fDynamicWhere.Xml);
oldlog := LogChanges;
fFetching := TRUE;
LogChanges := FALSE;
// book := nil;
data := Binary.Create;
Binary(data).CapacityIncrement := LocalDataStreamer.BufferSize;
try
for i := 0 to (ds.Params.Count - 1) do
ds.Params[i].Value := ParamByName(ds.Params[i].Name).Value;
LocalDataStreamer.WriteDataset(data, ds, [woRows, woSchema], -1);
if Active then
gofirst := FALSE
else
gofirst := TRUE;
if Assigned(fOnReceiveDataStream) then fOnReceiveDataStream(Self, data);
if Assigned(fBusinessRules) then fBusinessRules.OnReceiveDataStream(Self, data);
data.Position := 0;
// Reads the data
LocalDataStreamer.Initialize(data, aiRead);
if (LocalDataStreamer.DatasetCount = 0) then RaiseError('Stream does not contain any dataset');
if Opening then begin
if not (soIgnoreStreamSchema in fStreamingOptions) then LocalDataStreamer.ReadDataset(LogicalName, Self, TRUE, FALSE);
InitializeDataTable;
end;
LocalDataStreamer.ReadDataset(LogicalName, Self, FALSE);
{
if (moAllInOneFetch in MasterOptions) then begin
DoCascadeOperation(LocalDataStreamer, moAllInOneFetch);
end;}
LocalDataStreamer.Finalize;
if gofirst then First;
finally
fFetching := FALSE;
data.Free;
LogChanges := oldlog;
end;
finally
lConnection := nil;
end;
end;
procedure TDADataTable.DoOpen(IgnoreAutoFetchSettings: Boolean);
var i : integer;
begin
if Active or fOpening then Exit;
fOpening := TRUE;
try
{ Checks that all the lookup datasets are open. If not, we would get the error "Missing Data Provider"}
for i := 0 to (FieldCount-1) do
if Fields[i].Lookup and (Fields[i].LookupSource<>NIL) then begin
if (Fields[i].LookupSource is TDADataSource) then begin
if Assigned(TDADataSource(Fields[i].LookupSource).DataTable)
then TDADataSource(Fields[i].LookupSource).DataTable.Open;
end
else begin
if Assigned(Fields[i].LookupSource.DataSet)
then Fields[i].LookupSource.DataSet.Open;
end;
end;
if Assigned(BeforeOpen) then BeforeOpen(Self);
if Assigned(fBusinessRules) then fBusinessRules.BeforeOpen(Self);
try
if not fFetching then begin
if fMasterLink.Active then
FetchMastersDetails(nil, nil, IgnoreAutoFetchSettings) // This calls InitializeDataTable possibily applying a new schema
else
if RemoteFetchEnabled then LoadFromRemoteSource else LoadFromLocalSchema;
end;
if (moCascadeOpenClose in MasterOptions) then DoCascadeOperation(nil, moCascadeOpenClose);
if Assigned(AfterOpen) then AfterOpen(Self);
if Assigned(fBusinessRules) then fBusinessRules.AfterOpen(Self);
except
on E: Exception do begin
Close;
{$IFDEF DESIGNTIME}
if (csDesigning in ComponentState) then begin
SysUtils.Beep;
MessageDlg(E.Message, mtError, [mbOK], 0);
end
else
{$ENDIF DESIGNTIME}
raise;
end;
end;
finally
fOpening := FALSE;
end;
end;
procedure TDADataTable.Open;
begin
DoOpen(True);
end;
procedure TDADataTable.OnMasterChange(Sender: TObject);
begin
if (MasterSource <> nil) and (MasterSource.DataTable <> nil) then begin
if MasterSource.DataTable.fFetching then
exit;
end;
FetchMastersDetails;
end;
procedure TDADataTable.OnMasterDisable(Sender: TObject);
begin
end;
procedure TDADataTable.LoadFromRemoteSource(BookmarkPosition: boolean = FALSE);
begin
CheckProperties(True);
if Assigned(fOnBeforeDataRequestCall) then fOnBeforeDataRequestCall(Self, RemoteDataAdapter.Get_GetDataCall);
if Assigned(fBusinessRules) then fBusinessRules.OnBeforeDataRequestCall(Self, RemoteDataAdapter.Get_GetDataCall);
RemoteDataAdapter.Fill([self], BookmarkPosition, FieldCount = 0);
if Assigned(fOnAfterDataRequestCall) then fOnAfterDataRequestCall(Self, RemoteDataAdapter.Get_GetDataCall);
if Assigned(fBusinessRules) then fBusinessRules.OnAfterDataRequestCall(Self, RemoteDataAdapter.Get_GetDataCall);
end;
function TDADataTable.ApplyUpdates(RefetchAll: boolean = FALSE): boolean;
var
details: TList;
i: integer;
dt: TDADataTable;
begin
details:= GetDetailTablesforApplyUpdate;
try
// check RDA
CheckProperties;
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
{if dt.RemoteFetchEnabled then } dt.CheckProperties;
end;
//fOnBeforeApplyUpdates
if Assigned(fOnBeforeApplyUpdates) then fOnBeforeApplyUpdates(Self, fDelta);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fOnBeforeApplyUpdates) then dt.fOnBeforeApplyUpdates(dt, fDelta);
end;
//fBusinessRules.OnBeforeApplyUpdates
if Assigned(fBusinessRules) then fBusinessRules.OnBeforeApplyUpdates(Self, fDelta);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fBusinessRules) then dt.fBusinessRules.OnBeforeApplyUpdates(dt, fDelta);
end;
if RemoteFetchEnabled then begin
//fOnBeforeDataUpdateCall
if Assigned(fOnBeforeDataUpdateCall) then fOnBeforeDataUpdateCall(Self, RemoteDataAdapter.Get_UpdateDataCall);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fOnBeforeDataUpdateCall) then dt.fOnBeforeDataUpdateCall(dt, dt.RemoteDataAdapter.Get_UpdateDataCall);
end;
//fBusinessRules.OnBeforeDataUpdateCall
if Assigned(fBusinessRules) then fBusinessRules.OnBeforeDataUpdateCall(Self, RemoteDataAdapter.Get_UpdateDataCall);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fBusinessRules) then dt.fBusinessRules.OnBeforeDataUpdateCall(dt, dt.RemoteDataAdapter.Get_UpdateDataCall);
end;
result := RemoteDataAdapter.ApplyUpdates([self], RefetchAll);
//fOnAfterDataUpdateCall
if Assigned(fOnAfterDataUpdateCall) then fOnAfterDataUpdateCall(Self, RemoteDataAdapter.Get_UpdateDataCall);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fOnAfterDataUpdateCall) then dt.fOnAfterDataUpdateCall(dt, dt.RemoteDataAdapter.Get_UpdateDataCall);
end;
//fBusinessRules.OnAfterDataUpdateCall
if Assigned(fBusinessRules) then fBusinessRules.OnAfterDataUpdateCall(Self, RemoteDataAdapter.Get_UpdateDataCall);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fBusinessRules) then dt.fBusinessRules.OnAfterDataUpdateCall(dt, dt.RemoteDataAdapter.Get_UpdateDataCall);
end;
end
else begin
result := Local_ApplyUpdates(RefetchAll);
end;
//fOnAfterApplyUpdates
if Assigned(fOnAfterApplyUpdates) then fOnAfterApplyUpdates(Self);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fOnAfterApplyUpdates) then dt.fOnAfterApplyUpdates(dt);
end;
//fBusinessRules.OnAfterApplyUpdates
if Assigned(fBusinessRules) then fBusinessRules.OnAfterApplyUpdates(Self);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fBusinessRules) then dt.fBusinessRules.OnAfterApplyUpdates(dt);
end;
finally
details.Free;
end;
end;
procedure TDADataTable.LoadSchema(PreserveLookupFields : boolean = FALSE; PreserveClientCalcFields : boolean = FALSE);
begin
CheckProperties(True);
if Assigned(fOnBeforeSchemaCall) then fOnBeforeSchemaCall(Self, RemoteDataAdapter.Get_GetSchemaCall);
if Assigned(fBusinessRules) then fBusinessRules.OnBeforeSchemaCall(self, RemoteDataAdapter.Get_GetSchemaCall);
RemoteDataAdapter.FillSchema([self], PreserveLookupFields, PreserveClientCalcFields);
if Assigned(fOnAfterSchemaCall) then fOnAfterSchemaCall(Self, RemoteDataAdapter.Get_GetSchemaCall);
if Assigned(fBusinessRules) then fBusinessRules.OnAfterSchemaCall(self, RemoteDataAdapter.Get_GetSchemaCall);
end;
procedure TDADataTable.LoadScript(aDatasetName : string = '');
begin
CheckProperties(True);
if Assigned(fOnBeforeScriptCall) then fOnBeforeScriptCall(Self, RemoteDataAdapter.Get_GetScriptsCall);
if Assigned(fBusinessRules) then fBusinessRules.OnBeforeScriptCall(Self, RemoteDataAdapter.Get_GetScriptsCall);
RemoteDataAdapter.FillScripts([self]);
if Assigned(fOnAfterScriptCall) then fOnAfterScriptCall(Self, RemoteDataAdapter.Get_GetScriptsCall);
if Assigned(fBusinessRules) then fBusinessRules.OnAfterScriptCall(Self, RemoteDataAdapter.Get_GetScriptsCall);
end;
procedure TDADataTable.FetchMastersDetails(aMasterTable : TDADataTable = NIL; aRequestMappings : TStrings = NIL; IgnoreAutoFetchSettings: Boolean = False);
procedure CombineDynamicWhere(aWhereExpression:TDAWhereExpression);
begin
if fMasterMappingMode = mmWhere then begin
if fDynamicWhere.Expression = nil then
fDynamicWhere.Expression:= aWhereExpression
else
fDynamicWhere.Expression:= fDynamicWhere.NewBinaryExpression(fDynamicWhere.Expression,aWhereExpression,dboAnd);
end;
end;
procedure RevertDynamicWhere(aWhereExpression:TDAWhereExpression);
var
fUserWhereExpression: TDAWhereExpression;
begin
if fMasterMappingMode = mmWhere then begin
fUserWhereExpression:= nil;
if fDynamicWhere.Expression <> aWhereExpression then begin
fUserWhereExpression:= TDABinaryExpression(fDynamicWhere.Expression).Left;
TDABinaryExpression(fDynamicWhere.Expression).Left:=nil;
end;
fDynamicWhere.Clear;
fDynamicWhere.Expression:= fUserWhereExpression;
end;
end;
function GenerateWhereStatement: TDAWhereExpression;
var
lFieldName: string;
pos1, pos2: integer;
lfld1: TDAField;
lfld2: TDAField;
lExpression: TDAWhereExpression;
begin
//fDynamicWhere.Clear;
Pos1 := 1;
pos2 := 1;
Result:=nil;
while True do begin
if (Pos1 > Length(DetailFields)) and (Pos2 > Length(MasterFields)) then Break;
if ((Pos1 > Length(DetailFields)) and (Pos2 <= Length(MasterFields))) or
((Pos1 <= Length(DetailFields)) and (Pos2 > Length(MasterFields))) then
RaiseError('DetailFields should have same number of items as MasterFields');
{$WARN SYMBOL_DEPRECATED OFF}
lFieldName:= ExtractFieldName(DetailFields, Pos1);
{$WARN SYMBOL_DEPRECATED ON}
lfld1 := FindField(lFieldName);
if lfld1 = nil then RaiseError('Invalid field name %s in DetailFields', [lFieldName]);
{$WARN SYMBOL_DEPRECATED OFF}
lFieldName:= ExtractFieldName(MasterFields, Pos2);
{$WARN SYMBOL_DEPRECATED ON}
lfld2 := MasterSource.DataTable.Fields.FindField(lFieldName);
if lfld2 = nil then RaiseError('Invalid field name %s in MasterFields', [lFieldName]);
lExpression := fDynamicWhere.NewBinaryExpression(
fDynamicWhere.NewField('',lfld1.Name),
fDynamicWhere.NewConstant(lfld2.Value,lfld2.DataType),
dboEqual);
if Result <> nil then
Result:=fDynamicWhere.NewBinaryExpression(Result,lExpression,dboAnd)
else
Result:= lExpression;
end;
end;
var
master: TDataset;
par: TDARemoteRequestParam;
fld: TDAField;
key: string;
i: integer;
dofetch: boolean;
mappings : TStrings;
detailparam : TDAParam;
lmmWhereExpression: TDAWhereExpression;
begin
if RemoteFetchEnabled then CheckProperties
else if not(Assigned(LocalSchema) and Assigned(LocalDataStreamer)) then begin
if fOpening then InitializeDataTable;
Exit;
end;
//
//
// TODO: this doesnt properly use the new RDA's DMB yet. we need to discuss/rethink how to handle that!
//
//
mappings := NIL;
dofetch := (((dtAutoFetch in DetailOptions) or IgnoreAutoFetchSettings) {and RemoteFetchEnabled}) or (aMasterTable<>NIL);
if (aRequestMappings<>NIL) then mappings := aRequestMappings
else begin
case fMasterMappingMode of
mmDataRequest : mappings := MasterRequestMappings;
mmParams : mappings := MasterParamsMappings;
end;
end;
if (aMasterTable<>NIL)
then master := aMasterTable.Dataset
else master := fMasterLink.DataSet;
if master = nil then exit;
if (master.RecordCount = 0) then begin
if not Active then InitializeDataTable; // Master opened with 0 records and detail wasn't open yet
Exit;
end
else if (MasterSource = nil) then Exit;
if (master.State=dsBrowse) and not MasterSource.DataTable.Delta.IsNewRecord then begin
if dofetch then begin
// Determines if the details for this master have been fetched
key := IntToStr(MasterSource.DataTable.GetRowRecIDValue);
if (fFetchedMasters.IndexOf(key) >= 0) then Exit;
if (fMasterMappingMode = mmWhere) or ((mappings<>NIL) and (mappings.Count > 0)) then begin
lmmWhereExpression:=nil;
if RemoteFetchEnabled then begin
// remotemode
// If not, then assigns the param values from the current master record,
// invokes the remote call and loads the data
case MasterMappingMode of
mmWhere: begin
lmmWhereExpression:=GenerateWhereStatement;
end;
mmDataRequest : begin
for i := 0 to (mappings.Count - 1) do begin
par := nil;
if RemoteDataAdapter.Get_GetDataCall <> nil then
par := RemoteDataAdapter.Get_GetDataCall.Params.ParamByName(Trim(mappings.Names[i]));
if (par=NIL) then RaiseError('Invalid parameter name %s in master mappings', [Trim(mappings.Names[i])]);
fld := MasterSource.DataTable.Fields.FindField(Trim(mappings.Values[mappings.Names[i]]));
if (fld=NIL) then RaiseError('Invalid field name %s in master mappings', [Trim(mappings.Values[mappings.Names[i]])]);
if (par <> nil) and (fld <> nil) and not VarIsNull(fld.Value)
then par.AsVariant := fld.Value
end;
end;
mmParams : begin
// Fills it in
for i := 0 to (mappings.Count - 1) do begin
detailparam := Params.ParamByName(Trim(mappings.Names[i]));
if (detailparam=NIL) then RaiseError('Invalid parameter name %s in param mappings', [Trim(mappings.Names[i])]);
fld := MasterSource.DataTable.Fields.FindField(Trim(mappings.Values[mappings.Names[i]]));
if (fld=NIL) then RaiseError('Invalid field name %s in param mappings', [Trim(mappings.Values[mappings.Names[i]])]);
if (detailparam <> nil) and (fld <> nil) and not VarIsNull(fld.Value)
then detailparam.Value := fld.Value
end;
end;
end;
CombineDynamicWhere(lmmWhereExpression);
try
LoadFromRemoteSource;
finally
RevertDynamicWhere(lmmWhereExpression);
end;
try
fFetchedMasters.Add(key);
except
raise Exception.CreateFmt('Master record %s has been fetched twice', [key]);
end;
end { RemoteFetchEnabled }else begin
// localmode
// If not, then assigns the param values from the current master record,
// invokes the remote call and loads the data
case MasterMappingMode of
mmWhere: begin
lmmWhereExpression := GenerateWhereStatement;
end;
mmParams: begin
// Fills it in
for i := 0 to (mappings.Count - 1) do begin
detailparam := Params.ParamByName(Trim(mappings.Names[i]));
if (detailparam=NIL) then RaiseError('Invalid parameter name %s in param mappings', [Trim(mappings.Names[i])]);
fld := MasterSource.DataTable.Fields.FindField(Trim(mappings.Values[mappings.Names[i]]));
if (fld=NIL) then RaiseError('Invalid field name %s in param mappings', [Trim(mappings.Values[mappings.Names[i]])]);
if (detailparam <> nil) and (fld <> nil) and not VarIsNull(fld.Value) then detailparam.Value := fld.Value
end;
end;
mmDataRequest: raise Exception.Create('mmDataRequest mode only supported in RemoteFetchEnabled mode');
end;
CombineDynamicWhere(lmmWhereExpression);
try
LoadFromLocalSchema;
finally
RevertDynamicWhere(lmmWhereExpression);
end;
try
fFetchedMasters.Add(key);
except
raise Exception.CreateFmt('Master record %s has been fetched twice', [key]);
end;
end;
end else begin
{ ALEF: I removed the code below because it was never meant to be here to begin with. Very error prone.
Who added this???
// Automatics
for i := 0 to (DataRequestCall.Params.Count - 1) do begin
par := DataRequestCall.Params[i];
fld := MasterSource.DataTable.Fields.FindField(par.Name);
if (par <> nil) and (fld <> nil) and not VarIsNull(fld.Value) then par.Value := fld.Value;
end;}
RaiseError('There are no mappings defined. Cannot fetch records for detail table '+Name);
end;
end; {dofetch}
end;
end;
procedure TDADataTable.WriteDeltaToStream(aStreamer: TDADataStreamer);
var
i: integer;
details: TList;
lHasReducedDelta: Boolean;
oldMode: boolean;
begin
// And the details' updates (if specified)
details := GetDetailTablesforApplyUpdate(False);
try
lHasReducedDelta:= fHasReducedDelta;
if not aStreamer.SendReducedDelta then begin
if not lHasReducedDelta then
for i := 0 to (details.Count - 1) do begin
lHasReducedDelta:= TDADataTable(details[i]).fHasReducedDelta;
if lHasReducedDelta then Break;
end;
end;
oldMode:=aStreamer.SendReducedDelta;
if lHasReducedDelta then aStreamer.SendReducedDelta:=True;
try
// Writes its own updates
if self.HasDelta then aStreamer.WriteDelta(Self);
for i := 0 to (details.Count - 1) do
TDADataTable(details[i]).WriteDeltaToStream(aStreamer);
finally
aStreamer.SendReducedDelta := oldMode;
end;
finally
details.Free;
end;
end;
procedure TDADataTable.ReadDeltaFromStream(aStreamer: TDADataStreamer;aFailedDeltas:TList);
var
i: integer;
details: TList;
begin
// Reads its own updates
if aStreamer.FindDeltaIndex(Self.LogicalName) <> -1 then begin
Delta.Clear;
aStreamer.ReadDelta(Self);
if Delta.Count>0 then fHasReducedDelta := aStreamer.HasReducedDelta;
For i := 0 to Delta.Count-1 do
if Delta.Changes[i].Status = csFailed then
aFailedDeltas.Add(Delta.Changes[i]);
end;
// And the details' updates (if specified)
details := GetDetailTablesforApplyUpdate(False);
try
for i := 0 to (details.Count - 1) do
TDADataTable(details[i]).ReadDeltaFromStream(aStreamer, aFailedDeltas);
finally
details.Free;
end;
end;
procedure TDADataTable.ReadDeltaFromStream(aStreamer: TDADataStreamer);
var
List: TList;
begin
List:= TList.Create;
try
ReadDeltaFromStream(aStreamer,List);
finally
List.Free;
end;
end;
procedure TDADataTable.MergeDelta;
var
i, k, x: integer;
details: TList;
dt: TDADataTable;
// ok : boolean;
// failed, pending, resolved : integer;
oldval, newval, val : Variant;
fld : TDAField;
pkfields : string;
oldopt : TDARemoteUpdatesOptions;
oldlog : boolean;
keyvals : array of variant;
oldmastersource : TDADataSource;
lhasDelta: Boolean;
pk_array: array of boolean;
lReadOnly: boolean;
begin
details:=GetDetailTablesforApplyUpdate(False);
try
//fOnBeforeMergeDelta
if Assigned(fOnBeforeMergeDelta) then fOnBeforeMergeDelta(Self);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fOnBeforeMergeDelta) then dt.fOnBeforeMergeDelta(dt);
end;
//fBusinessRules.OnBeforeMergeDelta
if Assigned(fBusinessRules) then fBusinessRules.OnBeforeMergeDelta(Self);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fBusinessRules) then dt.fBusinessRules.OnBeforeMergeDelta(dt);
end;
oldopt := RemoteUpdatesOptions;
oldlog := LogChanges;
oldmastersource := MasterSource;
lhasDelta := Delta.Count > 0;
if lhasDelta then begin
RemoteUpdatesOptions := RemoteUpdatesOptions-[ruoOnPost];
LogChanges := FALSE;
// Disables the M/D relationship so that Locates can work in all cases (master or detail tables, regardless
// of their positioning)
MasterSource := NIL;
end;
try
pkfields := '';
for i := 0 to (Delta.KeyFieldCount-1) do
pkfields := pkfields+Delta.KeyFieldNames[i]+';';
pkfields := Copy(pkfields, 1, Length(pkfields)-1);
SetLength(keyvals, Delta.KeyFieldCount);
// Merges the updates
if (Delta.Count>0) then begin
SetLength(pk_array, Delta.LoggedFieldCount);
for i := 0 to Delta.LoggedFieldCount - 1 do
pk_array[i]:=False;
for i := 0 to Delta.KeyFieldCount - 1 do begin
x := Delta.IndexOfLoggedField(Delta.KeyFieldNames[i]);
if x <> -1 then pk_array[x]:=True;
end;
for i := (Delta.Count-1) downto 0 do begin
if (Delta[i].Status<>csResolved)
then Continue;
if (Delta[i].ChangeType<>ctDelete) then begin
if (Self.State in [dsEdit, dsInsert]) and (ruoOnPost in oldopt) then begin
// Merge the details
for x := 0 to (details.Count - 1) do
TDADataTable(details[x]).MergeDelta;
for x := 0 to (Delta.LoggedFieldCount-1) do begin
fld := FieldByName(Delta.LoggedFieldNames[x]);
newval := Delta[i].NewValueByName[fld.Name];
oldval := Delta[i].OldValueByName[fld.Name];
if fHasReducedDelta then begin
if not pk_array[x] and ROVariantsEqual(oldVal,newVal) then continue;
end;
if fld.ServerAutoRefresh or (not VarIsArray(newVal) and not ROVariantsEqual(newval,oldval)) then begin
VariantToFieldValue(Delta[i].NewValueByName[fld.Name], fld);
end;
end;
end
else begin
for k := 0 to (Delta.KeyFieldCount-1) do begin
val := Delta[i].OldValueByName[Delta.KeyFieldNames[k]];
keyvals[k] := val;
end;
// Locates the original record
First;
if not Locate(pkfields, keyvals, []) then Continue;
// Merge the details
for x := 0 to (details.Count - 1) do
TDADataTable(details[x]).MergeDelta;
// Merges its own updates
Edit;
for x := 0 to (Delta.LoggedFieldCount-1) do begin
fld := FieldByName(Delta.LoggedFieldNames[x]);
newval := Delta[i].NewValueByName[fld.Name];
oldval := Delta[i].OldValueByName[fld.Name];
if fHasReducedDelta then begin
if not pk_array[x] and ROVariantsEqual(oldVal,newVal) then continue;
end;
if fld.ServerAutoRefresh or (not VarIsArray(newVal) and (newval<>oldval)) then begin
lReadOnly := fld.ServerAutoRefresh and fld.ReadOnly;
if lReadOnly then fld.ReadOnly:=False;
VariantToFieldValue(Delta[i].NewValueByName[fld.Name], fld);
if lReadOnly then fld.ReadOnly:=True;
end;
end;
Post;
end;
end;
// Removes this merged change
Delta.Delete(i);
end;
end
// If there are no updates for this master, the children still need to be processed
else begin
// Merge the details
for x := 0 to (details.Count - 1) do
TDADataTable(details[x]).MergeDelta;
end;
finally
if lhasDelta then begin
RemoteUpdatesOptions := oldopt;
LogChanges := oldlog;
// Restores the M/D relationship
MasterSource := oldmastersource;
end;
//fOnAfterMergeDelta
if Assigned(fOnAfterMergeDelta) then fOnAfterMergeDelta(Self);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fOnAfterMergeDelta) then dt.fOnAfterMergeDelta(dt);
end;
//fBusinessRules.OnAfterMergeDelta
if Assigned(fBusinessRules) then fBusinessRules.OnAfterMergeDelta(Self);
for i := 0 to details.Count-1 do begin
dt:= TDADataTable(details[i]);
if Assigned(dt.fBusinessRules) then dt.fBusinessRules.OnAfterMergeDelta(dt);
end;
end;
finally
details.Free;
if Delta.Count = 0 then fHasReducedDelta:=False;
end;
end;
procedure TDADataTable.PackAllInOneFetchInfoArray(aDataTable : TDADataTable; OutArray: TDADatasetRequestInfoArray);
var outinfo : TDADatasetRequestInfo;
details : TList;
dt : TDADataTable;
i : integer;
begin
outinfo := outarray.Add;
outinfo.DatasetName := aDataTable.LogicalName;
outinfo.MaxRecords := aDataTable.MaxRecords;
outinfo.IncludeSchema := TRUE;
outinfo.Params := NIL;
details := aDataTable.GetDetailDataTables;
try
for i := 0 to (details.Count - 1) do begin
dt := TDADataTable(details[i]);
if (dtIncludeInAllInOneFetch in dt.DetailOptions)
then PackAllInOneFetchInfoArray(dt, OutArray);
end;
finally
details.Free;
end;
end;
function TDADataTable.FieldByName(const aName: string): TDAField;
begin
result := fFields.FieldByName(aName)
end;
function TDADataTable.ParamByName(const aName: string): TDAParam;
begin
result := fParams.ParamByName(aName)
end;
procedure TDADataTable.First;
begin
fDataset.First
end;
procedure TDADataTable.Last;
begin
fDataset.Last
end;
procedure TDADataTable.Prior;
begin
fDataset.Prior
end;
procedure TDADataTable.Sort(const FieldNames: array of string; const Directions: array of TDASortDirection);
var
i: integer;
begin
DoSort(FieldNames, Directions);
// Stores the new settings for convenience
SetLength(fSortDirections, Length(Directions));
for i := 0 to Length(Directions) - 1 do
fSortDirections[i] := Directions[i];
SetLength(fSortFieldNames, Length(FieldNames));
for i := 0 to Length(FieldNames) - 1 do
fSortFieldNames[i] := FieldNames[i];
end;
procedure TDADataTable.UnSort;
begin
Sort([], []);
end;
procedure TDADataTable.LoadFromStream(aStream: TStream);
var
//remfetch,
oldlogchanges, oldcascadeopenclose: boolean;
lStreamer: TDADataStreamer;
i: integer;
begin
Check(RemoteFetchEnabled, Name+'. Cannot do this operation when RemoteFetchEnabled is set to TRUE');
if RemoteDataAdapter <> nil then
lStreamer:=RemoteDataAdapter.DataStreamer
else
lStreamer:=LocalDataStreamer;
Check(lStreamer = nil, Name+'. RemoteDataAdapter or LocalDataStreamer must be assigned.');
Close;
oldlogchanges := LogChanges;
// remfetch := RemoteFetchEnabled;
oldcascadeopenclose := moCascadeOpenClose in fMasterOptions;
// RemoteFetchEnabled := FALSE;
LogChanges := FALSE;
if oldcascadeopenclose
then fMasterOptions := fMasterOptions - [moCascadeOpenClose];
try
fStreaming := True;
try
lStreamer.Initialize(aStream, aiRead);
if not (soIgnoreStreamSchema in fStreamingOptions) then
lStreamer.ReadDataset(LogicalName, Self, TRUE)
else
lStreamer.ReadDataset(LogicalName, Self, FALSE);
lStreamer.ReadDelta(Self);
if Delta <> nil then
For i:= 0 to Delta.Count-1 do
if fCurrRecId <= Delta.Changes[i].RecID then
fCurrRecId := Delta.Changes[i].RecID+1;
finally
fStreaming := False;
end;
finally
lStreamer.Finalize;
LogChanges := oldlogchanges;
// RemoteFetchEnabled := remfetch;
if oldcascadeopenclose then begin
fMasterOptions := fMasterOptions + [moCascadeOpenClose];
fOpening := True;
try
DoCascadeOperation(nil, moCascadeOpenClose);
finally
fOpening := False;
end;
end;
if Active then First;
end;
end;
procedure TDADataTable.SaveToStream(aStream: TStream);
var
lStreamer: TDADataStreamer;
OldMasterSource: TDADataSource;
begin
if (soDisableEventsWhileStreaming in fStreamingOptions) then DisableControls;
try
OldMasterSource := MasterSource;
MasterSource := nil;
fStreaming := True;
try
First; // Important!
if RemoteFetchEnabled then
lStreamer:= RemoteDataAdapter.DataStreamer
else
lStreamer:=LocalDataStreamer;
if lStreamer = nil then CheckProperties;
lStreamer.Initialize(aStream, aiWrite);
lStreamer.WriteDataset(Self, [woRows, woSchema]);
lStreamer.WriteDelta(Self);
lStreamer.Finalize;
finally
fStreaming := False;
MasterSource := OldMasterSource;
end;
finally
if (soDisableEventsWhileStreaming in fStreamingOptions) then EnableControls;
end;
end;
procedure TDADataTable.LoadFromFile(const aFileName: string);
var
fs: TFileStream;
oldval : boolean;
begin
oldval := RemoteFetchEnabled;
RemoteFetchEnabled := FALSE;
try
fs := TFileStream.Create(aFileName, fmOpenRead);
try
LoadFromStream(fs);
finally
fs.Free;
end;
finally
RemoteFetchEnabled := oldval;
end;
end;
procedure TDADataTable.SaveToFile(const aFileName: string);
var
fs: TFileStream;
begin
fs := TFileStream.Create(aFileName, fmCreate);
try
SaveToStream(fs);
finally
fs.Free;
end;
end;
procedure TDADataTable.SetParams(const Value: TDAParamCollection);
begin
fParams.Assign(Value);
end;
procedure TDADataTable.ClearFields;
var
i: integer;
begin
for i := 0 to FieldCount - 1 do
Fields[i].Value := Null;
end;
procedure TDADataTable.ClearRows;
var
CurChange: TDADeltaChange;
begin
while (RecordCount > 0) do begin
if (not LogChanges) and Assigned(Delta) then begin
CurChange := Delta.FindChange(RecIDValue);
if Assigned(CurChange) then
Delta.RemoveChange(CurChange);
end;
Delete;
end;
end;
function TDADataTable.GetState: TDataSetState;
begin
result := fDataset.State
end;
function TDADataTable.GetEditing: boolean;
begin
result := State in [dsEdit, dsInsert]
end;
function TDADataTable.GetPrepared: boolean;
begin
result := FALSE
end;
procedure TDADataTable.SetPrepared(Value: boolean);
begin
end;
function TDADataTable.GetText: string;
begin
result := ''
end;
procedure TDADataTable.SetText(const Value: string);
begin
end;
procedure TDADataTable.Notification(AComponent: TComponent;
Operation: TOperation);
var
i: Integer;
begin
inherited;
if (Operation = opRemove) then begin
if (AComponent = fLocalSchema) then fLocalSchema := nil;
if (AComponent = fRemoteDataAdapter) then fRemoteDataAdapter := nil;
if (AComponent = fLocalDataStreamer) then fLocalDataStreamer := nil;
if AComponent is TDataSource then begin
for i := 0 to Fields.Count - 1 do begin
if Fields[i].LookupSource = AComponent then
Fields[i].LookupSource := nil;
end;
end;
end;
end;
procedure TDADataTable.SetMasterSource(const Value: TDADataSource);
begin
fMasterLink.DataSource := Value;
end;
procedure TDADataTable.SetMasterFields(const Value: string);
begin
fMasterLink.FieldNames := Value;
end;
function TDADataTable.GetMasterRequestMappings: TStrings;
begin
result := fMasterRequestMappings;
end;
procedure TDADataTable.SetMasterRequestMappings(const Value: TStrings);
begin
fMasterRequestMappings.Assign(Value);
end;
function TDADataTable.GetDetailDataTables: TList;
var
i: integer;
ownerdt: TDADataTable;
dtdataset: IDADataTableDataset;
tmplist: TList;
begin
// This function only returns the linked datatables and removes duplicates
// from the GetDetailDataSets call. I assume the duplicates are because of
// the masterlink TDADatatables create.
result := TList.Create;
tmplist := TList.Create;
try
{$IFNDEF FPC}
Dataset.GetDetailDataSets(tmplist);
{$ENDIF}
for i := 0 to (tmplist.Count - 1) do begin
if not Supports(TDataset(tmplist[i]), IDADataTableDataset, dtdataset) then Continue;
ownerdt := dtdataset.GetDataTable;
if (result.IndexOf(ownerdt) < 0) then result.Add(ownerdt);
end;
finally
tmplist.Free;
end;
end;
function TDADataTable.GetDelta: IDADelta;
begin
if (fDelta = nil) then raise Exception.Create('Delta has not yet been initialized by the datatable');
result := fDelta;
end;
function TDADataTable.GetName: string;
begin
if (LogicalName = '') then
result := Name
else
result := LogicalName;
end;
procedure TDADataTable.DoAfterCloseDataset;
begin
CallScript('AfterClose');
end;
procedure TDADataTable.DoAfterOpenDataset;
begin
CallScript('AfterOpen');
if Assigned(fAfterOpenIDataset) then fAfterOpenIDataset(Self, '', ROGetTickCount-fOpenTick);
end;
procedure TDADataTable.DoBeforeCloseDataset;
begin
CallScript('BeforeClose');
end;
procedure TDADataTable.CloneSelectedRecord(Source: TDADataTable; DoPost: boolean = TRUE);
begin
CloneSelectedRecord(Source as IDADataset, DoPost);
end;
procedure TDADataTable.CloneSelectedRecord(const Source: IDADataset; DoPost: boolean = TRUE);
var
i: integer;
destfld,
srcfld: TDAField;
lreadonly: boolean;
begin
Insert;
for i := 0 to (Source.FieldCount - 1) do begin
srcfld := Source.Fields[i];
destfld := Fields.FindField(srcfld.Name);
lreadonly := destfld.ReadOnly;
destfld.ReadOnly := False;
try
if destfld <> nil then destfld.Value := srcfld.Value;
finally
destfld.ReadOnly := lreadonly;
end;
end;
if DoPost then Post;
end;
procedure TDADataTable.FreeBookmark(Bookmark: TBookmark);
begin
Dataset.FreeBookmark(Bookmark);
end;
function TDADataTable.GetBookmark: pointer;
begin
result := Dataset.GetBookmark;
end;
procedure TDADataTable.GotoBookmark(Bookmark: TBookmark);
begin
Dataset.GotoBookmark(Bookmark);
end;
function TDADataTable.GetRowRecIDValue: integer;
begin
result := fRecIDField.AsInteger
end;
procedure TDADataTable.DisableEventHandlers;
begin
DetachEventHooks(Dataset);
end;
procedure TDADataTable.EnableEventHandlers;
begin
AttachEventHooks(Dataset);
end;
procedure TDADataTable.Refresh;
begin
fDataset.Refresh;
end;
procedure TDADataTable.SetLocalDataStreamer(const Value: TDADataStreamer);
begin
fLocalDataStreamer := Value;
if (fLocalDataStreamer <> nil) then
fLocalDataStreamer.FreeNotification(Self);
end;
procedure TDADataTable.SetLocalSchema(const Value: TDASchema);
begin
fLocalSchema := Value;
if (fLocalSchema <> nil) then begin
fLocalSchema.FreeNotification(Self);
RemoteFetchEnabled := FALSE;
end;
end;
function TDADataTable.DataReaderFirst: boolean;
begin
result := RecordCount > 0;
if result then First;
end;
function TDADataTable.DataReaderNext: boolean;
begin
result := not EOF;
if result then Next;
end;
function TDADataTable.GetAsBoolean(Index: integer): boolean;
begin
result := fFields[Index].AsBoolean;
end;
function TDADataTable.GetAsBoolean(const FieldName: string): boolean;
begin
result := FieldByName(FieldName).AsBoolean;
end;
function TDADataTable.GetAsCurrency(Index: integer): Currency;
begin
Result:= fFields[Index].AsCurrency;
end;
function TDADataTable.GetAsCurrency(const FieldName: string): currency;
begin
result := FieldByName(FieldName).AsCurrency;
end;
function TDADataTable.GetAsDateTime(const FieldName: string): TDateTime;
begin
result := FieldByName(FieldName).AsDateTime;
end;
function TDADataTable.GetAsDateTime(Index: integer): TDateTime;
begin
result := fFields[Index].AsDateTime;
end;
function TDADataTable.GetAsFloat(const FieldName: string): double;
begin
result := FieldByName(FieldName).AsFloat;
end;
function TDADataTable.GetAsFloat(Index: integer): double;
begin
result := fFields[Index].AsFloat;
end;
function TDADataTable.GetAsInteger(Index: integer): integer;
begin
result := fFields[Index].AsInteger;
end;
function TDADataTable.GetAsInteger(const FieldName: string): integer;
begin
result := FieldByName(FieldName).AsInteger;
end;
function TDADataTable.GetAsString(const FieldName: string): string;
begin
result := FieldByName(FieldName).AsString;
end;
function TDADataTable.GetAsString(Index: integer): string;
begin
result := fFields[Index].AsString;
end;
function TDADataTable.GetAsVariant(const FieldName: string): variant;
begin
result := FieldByName(FieldName).Value;
end;
function TDADataTable.GetAsVariant(Index: integer): variant;
begin
result := fFields[Index].Value
end;
function TDADataTable.GetFieldIndexes(const aName: string): integer;
begin
result := fFields.FindItem(aName).Index
end;
function TDADataTable.GetFieldNames(Index: integer): string;
begin
result := fFields[Index].Name
end;
procedure TDADataTable.SetBusinessRulesID(const Value: string);
var
bizclass: TDADataTableRulesClass;
begin
if (Value = fBusinessRulesID) then Exit;
if Assigned(fBusinessRules) then begin
fBusinessRules.Detach(Self);
FreeAndNIL(fBusinessRules);
end;
fBusinessRulesID := Trim(Value);
if (fBusinessRulesID <> '') and not (csDesigning in ComponentState) then begin
Check(not FindDataTableRules(Value, bizclass), 'Invalid BusinessRulesID "%s"', [Value]);
fBusinessRules := bizclass.Create(Self);
fBusinessRules.Attach(Self);
end;
end;
function TDADataTable.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
result := inherited QueryInterface(IID, Obj);
if (result <> S_OK) and Assigned(fBusinessRules) then begin
// Users might introduce specific interfaces at the business rule level
// This allows to type cast the data table to any additional business oriented interface
// they decide to create.
result := fBusinessRules.QueryInterface(IID, Obj);
end;
end;
function TDADataTable.GetHasDelta: boolean;
begin
result := Assigned(fDelta) and (fDelta.Count > 0);
end;
function TDADataTable.GetHasDeltaRecursive: boolean;
var
lDetails: TList;
lTable: TDADataTable;
i: integer;
begin
result := Assigned(fDelta) and (fDelta.Count > 0);
if not result then begin
lDetails := nil;
if (moCascadeApplyUpdates in fMasterOptions) then try
lDetails := GetDetailDataTables;
for i := 0 to (lDetails.Count-1) do begin
lTable := TDADataTable(lDetails[i]);
if lTable.HasDeltaRecursive then begin
result := true;
exit;
end;
end;
finally
lDetails.Free;
end;
end;
end;
function TDADataTable.GetMasterDataTable: TDADataTable;
var lDatatableDataset : IDADataTableDataset;
begin
if Supports(fMasterLink.DataSet, IDADataTableDataset, lDatatableDataset)
then result := lDatatableDataset.GetDataTable
else result := NIL;
end;
function TDADataTable.GetRecNo: integer;
begin
result := fDataset.RecNo
end;
procedure TDADataTable.SetRecNo(const Value: integer);
begin
fDataset.RecNo := Value
end;
function TDADataTable.GetFieldsProperty: TDAFieldCollection;
begin
result := GetFields;
end;
function TDADataTable.GetActiveProperty: boolean;
begin
result := GetActive();
end;
procedure TDADataTable.SetActiveProperty(const Value: boolean);
begin
SetActive(Value);
end;
function TDADataTable.GetParamsProperty: TDAParamCollection;
begin
result := GetParams();
end;
{$IFNDEF LINUX}
function TDADataTable.InterfaceSupportsErrorInfo(const iid: TGUID): HResult;
begin
if GetInterfaceEntry(iid) <> nil then
Result := S_OK
else
Result := S_FALSE;
end;
function TDADataTable.SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult;
begin
Result := uDAEngine.DAHandleSafeCallException(self,ExceptObject, ExceptAddr);
end;
{$ENDIF}
procedure TDADataTable.CancelUpdates(IncludeDetails: boolean);
var list : TList;
i, orignextinc : integer;
wasfiltered,
remotefetch : boolean;
lOldMasterFields: string;
begin
if Editing then Cancel;
if not LogChanges then Exit;
DisableControls;
wasfiltered := Filtered;
Filtered := FALSE;
try
// Truns off the remote fetching for this datatable and its details
remotefetch := RemoteFetchEnabled;
RemoteFetchEnabled := FALSE;
if IncludeDetails then list := GetDetailDataTables else list := TList.Create;
// Disable the log of changes (we're about to make a bunch!)
LogChanges := FALSE;
// Saves the current recinc (we'll change this during the restore)
orignextinc := CurrRecId;
try
lOldMasterFields := MasterFields;
MasterFields := '';
try
// Reverts the records to the original state
for i := 0 to (Delta.Count-1) do
InternalCancelUpdateChange(Delta[i]);
finally
MasterFields := lOldMasterFields;
end;
// Cancels the updates for the details
for i := 0 to list.Count-1 do begin
TDADataTable(list[i]).CancelUpdates(TRUE);
end;
// Erases the delta
Delta.Clear;
finally
fHasReducedDelta:=False;
list.Free;
CurrRecId := orignextinc;
LogChanges := TRUE;
RemoteFetchEnabled := remotefetch;
end;
finally
Filtered := wasfiltered;
EnableControls;
end;
end;
procedure TDADataTable.DoBeforeOpenDataset;
begin
CallScript('BeforeOpen');
fOpenTick := ROGetTickCount;
if Assigned(fBeforeOpenIDataset) then fBeforeOpenIDataset(Self);
end;
function TDADataTable.Lookup(const KeyFields: string;
const KeyValues: Variant; const ResultFields: string): Variant;
begin
result := fDataset.Lookup(KeyFields, KeyValues, ResultFields);
end;
function TDADataTable.GetIsEmpty: boolean;
begin
result := fDataset.IsEmpty;
end;
function TDADataTable.GetMasterParamsMappings: TStrings;
begin
result := fMasterParamsMappings
end;
procedure TDADataTable.SetMasterParamsMappings(const Value: TStrings);
begin
fMasterParamsMappings.Assign(Value);
end;
function TDADataTable.GetLogicalName: string;
begin
result := fLogicalName;
end;
function TDADataTable.GetReadOnly: boolean;
begin
result := FALSE;
end;
procedure TDADataTable.SetReadOnly(const Value: boolean);
begin
// By default this property cannot be set. Raising exceptions creates problems
// at design time and it's useless
end;
procedure TDADataTable.SetScriptCode(const Value: TStrings);
begin
fScriptCode.Assign(Value);
end;
procedure TDADataTable.CallScript(const aEvent: string);
begin
if Assigned(ScriptingProvider) and (ScriptCode.Count > 0) then begin
(ScriptingProvider as IDADataTableScriptingProvider).RunDataTableScript(self, ScriptCode.Text, aEvent, rslPascalScript);
end;
end;
function TDADataTable.FindField(const aName: string): TDAField;
begin
result := fFields.FindField(aName);
end;
procedure TDADataTable.AddRecord(const FieldNames: array of string;
const FieldValues: array of Variant);
var i : integer;
begin
Insert;
for i := 0 to Length(FieldNames)-1 do
FieldByName(FieldNames[i]).Value := FieldValues[i];
Post;
end;
procedure TDADataTable.SetLogicalName(aName: string);
begin
fLogicalName := aName;
end;
function TDADataTable.GetDeltaInitialized: boolean;
begin
result := fDelta<>NIL
end;
procedure TDADataTable.NotifyFieldsClear;
var
i, lLockCount: integer;
begin
// This method patches VCL issue with notification
// of datasources when clearing fields and controls is disabled
lLockCount := 0;
while DataSet.ControlsDisabled do begin
inc(lLockCount);
DataSet.EnableControls;
end;
TDataSetHack(DataSet).DataEvent(deFieldListChange, 0);
for i := 0 to lLockCount - 1 do begin
DataSet.DisableControls;
end;
end;
function TDADataTable.GetOnAfterOpen: TDAAfterOpenDatasetEvent;
begin
result := fAfterOpenIDataset;
end;
function TDADataTable.GetOnBeforeOpen: TDABeforeOpenDatasetEvent;
begin
result := fBeforeOpenIDataset;
end;
procedure TDADataTable.SetOnAfterOpen(
const Value: TDAAfterOpenDatasetEvent);
begin
fAfterOpenIDataset := Value;
end;
procedure TDADataTable.SetOnBeforeOpen(
const Value: TDABeforeOpenDatasetEvent);
begin
fBeforeOpenIDataset := Value;
end;
function TDADataTable.GetOnAfterExecute: TDAAfterExecuteCommandEvent;
begin
NotSupported();
end;
function TDADataTable.GetOnBeforeExecute: TDABeforeExecuteCommandEvent;
begin
NotSupported();
end;
procedure TDADataTable.SetOnAfterExecute(
const Value: TDAAfterExecuteCommandEvent);
begin
NotSupported();
end;
procedure TDADataTable.SetOnBeforeExecute(
const Value: TDABeforeExecuteCommandEvent);
begin
NotSupported();
end;
function TDADataTable.GetOnExecuteError: TDAExecuteCommandErrorEvent;
begin
NotSupported();
end;
function TDADataTable.GetOnOpenError: TDAOpenDatasetErrorEvent;
begin
NotSupported();
end;
procedure TDADataTable.SetOnExecuteError(
const Value: TDAExecuteCommandErrorEvent);
begin
NotSupported();
end;
procedure TDADataTable.SetOnOpenError(
const Value: TDAOpenDatasetErrorEvent);
begin
NotSupported();
end;
function TDADataTable.GetCurrRecId: integer;
begin
result := fCurrRecId;
end;
procedure TDADataTable.SetCurrRecId(const Value: integer);
begin
fCurrRecId := Value;
end;
function TDADataTable.GetAutoIncs: TAutoIncArray;
begin
result := fAutoIncs;
end;
procedure TDADataTable.SetAutoIncs(const Value: TAutoIncArray);
begin
fAutoIncs := Value;
end;
function TDADataTable.CreateAutoIncArray: TAutoIncArray;
var i: integer;
begin
SetLength(result, Fields.Count);
for i := 0 to Fields.Count-1 do result[i] := -1;
end;
function TDADataTable.GetCurrentRecIdValue: integer;
begin
result := fCurrRecId;
end;
procedure TDADataTable.SetCurrentRecIdValue(Value: integer);
begin
fCurrRecId := Value;
end;
procedure TDADataTable.InternalAfterFieldUpdate(Sender: TDACustomField);
begin
if assigned(fAfterFieldChange) and (Sender is TDAField) then
fAfterFieldChange(self, TDAField(Sender));
end;
procedure TDADataTable.InternalBeforeFieldUpdate(Sender: TDACustomField);
begin
if assigned(fBeforeFieldChange) and (Sender is TDAField) then
fBeforeFieldChange(self, TDAField(Sender));
end;
procedure TDADataTable.InternalSetFetching(aFetching: boolean);
begin
fFetching := aFetching;
end;
procedure TDADataTable.SetCustomAttributes(const Value: TStrings);
begin
fCustomAttributes.Assign(Value);
end;
function TDADataTable.Local_ApplyUpdates(RefetchAll: boolean): boolean;
function UnpackDeltas(var lStruct: TDADeltaStruct): TDABusinessProcessor;
var
j: integer;
lBizProc: TDABusinessProcessor;
lDetails: TDADatasetRelationshipList;
lFound: boolean;
begin
result := nil;
lStruct := nil;
// Reads the deltas.
lFound := false;
{ Tries to locate a user-defined business processor }
if LocalSchema.Owner <> nil then
for j := 0 to (LocalSchema.Owner.ComponentCount - 1) do begin
if (LocalSchema.Owner.Components[j] is TDABusinessProcessor) then begin
lBizProc := TDABusinessProcessor(LocalSchema.Owner.Components[j]);
if SameText(lBizProc.ReferencedDataset, Self.LogicalName) then begin
lStruct := TDADeltaStruct.Create(Self.Delta, lBizProc);
lFound := true;
Break;
end;
end;
end;
{ Either creates one}
if not lFound then begin
lBizProc := TDABusinessProcessor.Create(nil);
lBizProc.ReferencedDataset := Self.LogicalName;
lBizProc.Schema := LocalSchema;
Result := lBizProc;
lStruct := TDADeltaStruct.Create(Self.Delta, lBizProc);
end;
{ Sets the master/detail relationships }
if (LocalSchema.RelationShips.Count > 0) then begin
lDetails := TDADatasetRelationshipList.Create;
try
LocalSchema.RelationShips.GetDetails(lStruct.BusinessProcessor.ReferencedDataset, lDetails);
if (lDetails.Count <> 0) then begin
{ Prepares an array with the references to the detail deltas that will be used later on to adjust
autoincs, etc. }
for j := 0 to lDetails.Count - 1 do begin
if lDetails[j].DetailDatasetName = LogicalName then begin
lStruct.DetailDeltas.Add(lStruct.Delta);
lStruct.RelationShips.Add(lDetails[j]);
end;
end;
end;
finally
lDetails.Free;
end;
end;
end;
var
FLocalConnection: IDAConnection;
lProcessedDeltas: TStringList;
lStruct: TDADeltaStruct;
lBizProc: TDABusinessProcessor;
i, j: integer;
begin
Result:=False;
CheckProperties;
FLocalConnection := LocalSchema.ConnectionManager.NewConnection(LocalConnection);
if (Delta = nil) or (Delta.Count = 0) then Exit;
lBizProc := UnpackDeltas(lStruct);
try
{if TriggerTransactionEvent(fOnUpdateDataBeginTransaction) then} FLocalConnection.BeginTransaction;
try
if (LocalSchema.UpdateRules.Count = 0) then begin
lStruct.BusinessProcessor.ProcessDelta(FLocalConnection, lStruct.Delta, AllChanges);
end
else begin
lProcessedDeltas := TStringList.Create;
try
for i := 0 to (LocalSchema.UpdateRules.Count - 1) do begin
// Processes them in the order defined in the schema
if LocalSchema.UpdateRules[i].DatasetName = LogicalName then begin
// Adds the dataset name to the list of processed deltas. Those that don't have update rules will be processed later
lProcessedDeltas.Add(LogicalName);
// Processes the delta
lStruct.BusinessProcessor.ProcessDelta(FLocalConnection, lStruct.Delta, LocalSchema.UpdateRules[i].ChangeTypes);
if (ctInsert in LocalSchema.UpdateRules[i].ChangeTypes) then begin
for j := 0 to (lStruct.DetailDeltas.Count - 1) do
lStruct.BusinessProcessor.SynchronizeAutoIncs(lStruct.Delta, lStruct.DetailDeltas[j], lStruct.RelationShips[j]);
end;
end;
end;
// Processes the deltas for which update rules were not defined
if lProcessedDeltas.IndexOf(LogicalName) = -1 then
lStruct.BusinessProcessor.ProcessDelta(FLocalConnection, lStruct.Delta, AllChanges);
finally
lProcessedDeltas.Free;
end;
end;
if FLocalConnection.InTransaction {and TriggerTransactionEvent(fOnUpdateDataCommitTransaction)} then FLocalConnection.CommitTransaction;
MergeDelta;
Result:=True;
except
on E: Exception do begin
if FLocalConnection.InTransaction {and TriggerTransactionEvent(fOnUpdateDataRollBackTransaction)} then FLocalConnection.RollbackTransaction;
raise;
end;
end;
finally
if lStruct <> nil then lStruct.Free;
if lBizProc <> nil then lBizProc.Free;
end;
if RefetchAll and result then begin
if Active then Close;
Open;
end;
end;
procedure TDADataTable.GetDetailTablesforAllinOneFetch(aRemote, aLocal:TList; aRecursive: boolean);
var
i: integer;
dt: TDADataTable;
dtList: TList;
scc: IDASimpleClonedCursorsSupport;
begin
if (moAllInOneFetch in fMasterOptions) then begin
dtList:=GetDetailDataTables;
try
for i := 0 to dtList.Count-1 do begin
dt := TDADataTable(dtList[i]);
if (dtIncludeInAllInOneFetch in dt.DetailOptions) then begin
if (dt.QueryInterface(IDASimpleClonedCursorsSupport, scc) = S_OK) and (scc.GetSimpleCloneSource <> nil) then begin
dt:= TDADatatable(scc.GetSimpleCloneSource);
end;
if self.RemoteFetchEnabled and dt.RemoteFetchEnabled and (dt.RemoteDataAdapter = Self.RemoteDataAdapter) then begin
if aRemote.IndexOf(dt) = -1 then aRemote.Add(dt);
end
else begin
if aLocal.IndexOf(dt) = -1 then aLocal.Add(dt);
end;
if aRecursive then dt.GetDetailTablesforAllinOneFetch(aRemote,aLocal, aRecursive);
end;
end;
finally
dtList.Free;
end;
end
end;
function TDADataTable.GetDetailTablesforApplyUpdate(aRecursive: boolean): TList;
var
i: integer;
dt: TDADataTable;
dtList, dtlist1: TList;
scc: IDASimpleClonedCursorsSupport;
begin
Result:= TList.Create;
if (moCascadeApplyUpdates in fMasterOptions) then begin
dtList:=GetDetailDataTables;
try
for i := 0 to dtList.Count-1 do begin
dt := TDADataTable(dtList[i]);
if dt.Active and (dtCascadeApplyUpdates in dt.DetailOptions) then begin
if (dt.QueryInterface(IDASimpleClonedCursorsSupport, scc) = S_OK) and (scc.GetSimpleCloneSource <> nil) then begin
dt:= TDADatatable(scc.GetSimpleCloneSource);
end;
if Result.IndexOf(dt) = -1 then Result.Add(dt);
if aRecursive then begin
dtlist1:= dt.GetDetailTablesforApplyUpdate(aRecursive);
try
Result.Assign(dtlist1,laOr);
finally
dtlist1.Free;
end;
end;
end;
end;
finally
dtList.Free;
end;
end
end;
procedure TDADataTable.CancelUpdateChange(Change: TDADeltaChange;IncludeDetails : boolean = TRUE);
var
orignextinc : integer;
wasfiltered,
remotefetch : boolean;
lOldMasterFields: string;
details: TList;
i,j,k: integer;
detailChange: TDADeltaChange;
ChangePKValueArray: array of Variant;
lNeedDeleteChange: boolean;
keyvalue: variant;
begin
if Editing then Cancel;
if not LogChanges then Exit;
DisableControls;
wasfiltered := Filtered;
Filtered := FALSE;
try
// Truns off the remote fetching for this datatable and its details
remotefetch := RemoteFetchEnabled;
RemoteFetchEnabled := FALSE;
// Disable the log of changes (we're about to make a bunch!)
LogChanges := FALSE;
// Saves the current recinc (we'll change this during the restore)
orignextinc := CurrRecId;
try
lOldMasterFields := MasterFields;
MasterFields := '';
try
// Reverts the records to the original state
if IncludeDetails then begin
SetLength(ChangePKValueArray,Change.Delta.KeyFieldCount);
For i:=1 to Change.Delta.KeyFieldCount do begin
if Change.ChangeType = ctInsert then
keyvalue:=Change.NewValueByName[Change.Delta.KeyFieldNames[i-1]]
else
keyvalue:=Change.OldValueByName[Change.Delta.KeyFieldNames[i-1]];
ChangePKValueArray[0]:=keyvalue;
end;
details:=GetDetailTablesforApplyUpdate(False);
try
for i:=0 to details.Count-1 do begin
for j:=0 to TDADataTable(details[i]).Delta.Count-1 do begin
detailChange :=TDADataTable(details[i]).Delta.Changes[j];
if detailChange.Status <> csResolved then begin
lNeedDeleteChange:= True;
for k:=0 to Change.Delta.KeyFieldCount-1 do begin
if detailChange.ChangeType = ctInsert then
keyvalue:=detailChange.NewValueByName[Change.Delta.KeyFieldNames[k]]
else
keyvalue:=detailChange.oldValueByName[Change.Delta.KeyFieldNames[k]];
if not VarSameValue(keyValue, ChangePKValueArray[k]) then begin
lNeedDeleteChange:= False;
Break;
end;
end;
if lNeedDeleteChange then TDADataTable(details[i]).CancelUpdateChange(detailChange,IncludeDetails);
end;
end;
end;
finally
details.Free;
end;
end;
InternalCancelUpdateChange(change);
Delta.RemoveChange(change);
finally
if Delta.Count = 0 then fHasReducedDelta:=False;
MasterFields := lOldMasterFields;
end;
finally
CurrRecId := orignextinc;
LogChanges := TRUE;
RemoteFetchEnabled := remotefetch;
end;
finally
Filtered := wasfiltered;
EnableControls;
end;
end;
procedure TDADataTable.InternalCancelUpdateChange(Change: TDADeltaChange);
var
i, x : integer;
fldname : string;
fldvalue : Variant;
details: TList;
RecID:string;
begin
case Change.ChangeType of
ctDelete : begin
CurrRecId := change.RecID; // We want the same autoinc regenerated
RecID:=IntToStr(Change.RecID);
Insert;
for x := 0 to (Delta.LoggedFieldCount-1) do begin
fldname := Delta.LoggedFieldNames[x];
fldvalue := change.OldValues[x];
VariantToFieldValue(fldValue, FieldByName(fldname));
end;
Post;
details := GetDetailDataTables;
try
for x := 0 to (details.Count-1) do begin
i:=TDADataTable(details[x]).fFetchedMasters.IndexOf(RecID);
if i<>-1 then TDADataTable(details[x]).fFetchedMasters.Delete(i);
end;
finally
details.Free;
end;
end;
else begin
if not Locate(RecIDFieldName, change.RecID, []) then RaiseError('Couldn''t find record #'+FormatRecIDString(change.RecID));
if (change.ChangeType=ctInsert) then Delete
else begin
Edit;
for x := 0 to (Delta.LoggedFieldCount-1) do begin
fldname := Delta.LoggedFieldNames[x];
fldvalue := change.OldValues[x];
if fHasReducedDelta and ROVariantsEqual(fldvalue, change.NewValues[x]) then Continue;
VariantToFieldValue(fldValue, FieldByName(fldname));
end;
Post;
end;
end;
end;
end;
procedure TDADataTable.CheckProperties(ACheckRemoteFetching: Boolean=False);
begin
if LogicalName = '' then raise Exception.Create(Name+'.LogicalName must be specified.');
if RemoteFetchEnabled or ACheckRemoteFetching then begin
Check(RemoteDataAdapter = nil, Name+'.RemoteDataAdapter must be assigned.');
end
else begin
Check(LocalDataStreamer = nil , Name+'.LocalDataStreamer must be assigned.');
Check(LocalSchema = nil, Name+'.LocalSchema must be assigned.');
LocalSchema.CheckProperties;
end;
end;
procedure TDADataTable.ExpessionEvaluatorGetValue(
Sender: TDAExpressionEvaluator; const aIdentifier: string;
out aValue: Variant);
begin
aValue := Fields.FieldByName(aIdentifier).Value;
end;
function TDADataTable.GetDynamicWhere: TDAWhereBuilder;
begin
Result := fDynamicWhere;
end;
procedure TDADataTable.SetDynamicWhere(const Value: TDAWhereBuilder);
begin
if Value <> nil then
FDynamicWhere.Xml := Value.Xml
else
FDynamicWhere.Clear;
end;
function TDADataTable.SQLContainsDynamicWhere: boolean;
begin
Result:=False;
// Not implemented in DataTables
end;
{ TDADataSource }
constructor TDADataSource.Create(aOwner: TComponent);
begin
inherited;
end;
destructor TDADataSource.Destroy;
begin
inherited;
end;
function TDADataSource.GetActive: boolean;
begin
result := (fDataTable <> nil) and fDataTable.Active
end;
function TDADataSource.GetDataset: TDataset;
begin
result := nil;
end;
function TDADataSource.GetOpening: boolean;
begin
result := (fDataTable <> nil) and fDataTable.Opening
end;
procedure TDADataSource.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
if (AComponent = fDataTable) then begin
fDataTable := nil;
inherited Dataset := nil;
end;
end;
procedure TDADataSource.SetDataset(const Value: TDataset);
begin
end;
procedure TDADataSource.SetDataTable(const Value: TDADataTable);
begin
fDataTable := Value;
if (fDataTable <> nil) then begin
fDataTable.FreeNotification(Self);
inherited Dataset := fDataTable.Dataset;
end
else
inherited Dataset := nil;
end;
{ TDABusinessRules }
constructor TDABusinessRules.Create;
begin
inherited;
end;
destructor TDABusinessRules.Destroy;
begin
inherited;
end;
function TDABusinessRules._AddRef: Integer;
begin
result := -1;
end;
function TDABusinessRules._Release: Integer;
begin
result := -1;
end;
{ TDADataTableRules }
constructor TDADataTableRules.Create(aDataTable: TDADataTable);
begin
inherited Create;
Check(not Assigned(aDatatable), 'DataTable cannot be NIL');
fDetails := TStringList.Create;
fDetails.Sorted := TRUE;
fDetails.Duplicates := dupError;
fDataTable := aDataTable;
end;
destructor TDADataTableRules.Destroy;
begin
fDetails.Free;
inherited;
end;
procedure TDADataTableRules.AfterCancel(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.AfterClose(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.AfterDelete(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.AfterEdit(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.AfterInsert(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.AfterOpen(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.AfterPost(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.AfterRefresh(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.AfterScroll(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.BeforeCancel(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.BeforeClose(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.BeforeDelete(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.BeforeEdit(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.BeforeInsert(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.BeforeOpen(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.BeforePost(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.BeforeRefresh(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.BeforeScroll(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.OnCalcFields(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.OnNewRecord(Sender: TDADataTable);
begin
end;
procedure TDADataTableRules.OnDeleteError(DataTable: TDADataTable;
Error: EDatabaseError; var Action: TDataAction);
begin
end;
procedure TDADataTableRules.OnEditError(DataTable: TDADataTable;
Error: EDatabaseError; var Action: TDataAction);
begin
end;
procedure TDADataTableRules.Attach(aDataTable: TDADataTable);
begin
RefreshDetails;
end;
procedure TDADataTableRules.Detach(aDataTable: TDADataTable);
begin
fDetails.Clear;
end;
procedure TDADataTableRules.Append;
begin
fDataTable.Append();
end;
procedure TDADataTableRules.Cancel;
begin
fDataTable.Cancel();
end;
procedure TDADataTableRules.Delete;
begin
fDataTable.Delete();
end;
procedure TDADataTableRules.Edit;
begin
fDataTable.Edit();
end;
procedure TDADataTableRules.First;
begin
fDataTable.First();
end;
procedure TDADataTableRules.Insert;
begin
fDataTable.Insert();
end;
procedure TDADataTableRules.Last;
begin
fDataTable.Last();
end;
procedure TDADataTableRules.Next;
begin
fDataTable.Next();
end;
procedure TDADataTableRules.Post;
begin
fDataTable.Post();
end;
procedure TDADataTableRules.Prior;
begin
fDataTable.Prior();
end;
function TDADataTableRules.GetBOF: Boolean;
begin
result := fDataTable.BOF;
end;
function TDADataTableRules.GetEOF: Boolean;
begin
result := fDataTable.EOF;
end;
function TDADataTableRules.GetRecordCount: Integer;
begin
result := fDataTable.RecordCount;
end;
function TDADataTableRules.Locate(const aKeyFields: String; const aKeyValues: Variant; aOptions: TLocateOptions = []): boolean;
begin
result := fDataTable.Locate(aKeyFields, aKeyValues, aOptions);
end;
function TDADataTableRules.GetDetails(Index: integer): TDADataTable;
begin
result := TDADataTable(fDetails[Index])
end;
function TDADataTableRules.GetDetailsCount: integer;
begin
result := fDetails.Count
end;
function TDADataTableRules.FindDetail(
const aLogicalName: string): TDADataTable;
var i : integer;
begin
result := NIL;
i := fDetails.IndexOf(aLogicalName);
if (i>=0) then result := TDADataTable(fDetails.Objects[i]);
end;
function TDADataTableRules.DetailByName(
const aLogicalName: string): TDADataTable;
begin
result := FindDetail(aLogicalName);
if (result=NIL)
then raise Exception.CreateFmt('Cannot find the detail DataTable %s ', [aLogicalName]);
end;
procedure TDADataTableRules.RefreshDetails;
var lList : TList;
i : integer;
lLogicalName : string;
begin
lList := DataTable.GetDetailDataTables;
fDetails.Clear;
try
for i := 0 to (lList.Count-1) do begin
lLogicalName := TDADataTable(lList[i]).LogicalName;
if (lLogicalName<>'')
then fDetails.AddObject(lLogicalName, lList[i]);
end;
finally
lList.Free;
end;
end;
function TDADataTableRules.GetDetailOptions: TDADetailOptions;
begin
result := DataTable.DetailOptions
end;
function TDADataTableRules.GetMasterOptions: TDAMasterOptions;
begin
result := DataTable.MasterOptions
end;
procedure TDADataTableRules.SetDetailOptions(Value: TDADetailOptions);
begin
DataTable.DetailOptions := Value
end;
procedure TDADataTableRules.SetMasterOptions(Value: TDAMasterOptions);
begin
DataTable.MasterOptions := Value
end;
function TDADataTableRules.GetRecNo: integer;
begin
result := fDataTable.RecNo
end;
procedure TDADataTableRules.SetRecNo(Value: integer);
begin
fDataTable.RecNo := Value
end;
procedure TDADataTableRules.OnFilterRecord(DataTable: TDADataTable;
var Accept: boolean);
begin
end;
procedure TDADataTableRules.OnPostError(DataTable: TDADataTable;
Error: EDatabaseError; var Action: TDataAction);
begin
end;
function TDADataTableRules.Lookup(const KeyFields: string;
const KeyValues: Variant; const ResultFields: string): Variant;
begin
result := fDataTable.Lookup(KeyFields, KeyValues, ResultFields);
end;
function TDADataTableRules.GetIsEmpty: boolean;
begin
result := fDataTable.IsEmpty
end;
function TDADataTableRules.GetState: TDatasetState;
begin
result := fDataTable.State
end;
function TDADataTableRules.IsFieldNull(
const FieldIndexOrName: Variant): boolean;
var fld : TDAField;
begin
case VarType(FieldIndexOrName) of
varString, varOleStr, varStrArg : fld := DataTable.FieldByName(VarToStr(FieldIndexOrName));
else fld := DataTable.Fields[FieldIndexOrName];
end;
result := fld.IsNull;
end;
procedure TDADataTableRules.ClearField(const FieldIndexOrName: Variant);
var fld : TDAField;
begin
case VarType(FieldIndexOrName) of
varString, varOleStr, varStrArg : fld := DataTable.FieldByName(VarToStr(FieldIndexOrName));
else fld := DataTable.Fields[FieldIndexOrName];
end;
fld.Clear;
end;
function TDADataTableRules.GetDataTable: TDADataTable;
begin
result := fDataTable;
end;
procedure TDADataTableRules.ApplyRange;
begin
(fDataTable as IDARangeController).ApplyRange
end;
procedure TDADataTableRules.CancelRange;
begin
(fDataTable as IDARangeController).CancelRange
end;
procedure TDADataTableRules.EditRangeEnd;
begin
(fDataTable as IDARangeController).EditRangeEnd
end;
procedure TDADataTableRules.EditRangeStart;
begin
(fDataTable as IDARangeController).EditRangeStart
end;
procedure TDADataTableRules.SetRange(const StartValues,
EndValues: array of const);
begin
(fDataTable as IDARangeController).SetRange(StartValues, EndValues);
end;
procedure TDADataTableRules.SetRangeEnd;
begin
(fDataTable as IDARangeController).SetRangeEnd
end;
procedure TDADataTableRules.SetRangeStart;
begin
(fDataTable as IDARangeController).SetRangeStart
end;
procedure TDADataTableRules.Close;
begin
fDataTable.Close;
end;
procedure TDADataTableRules.Open;
begin
fDataTable.Open;
end;
function TDADataTableRules.GetActive: boolean;
begin
result := fDataTable.Active;
end;
procedure TDADataTableRules.SetActive(const Value: boolean);
begin
fDataTable.Active := Value;
end;
procedure TDADataTableRules.OnAfterApplyUpdates(DataTable: TDADataTable);
begin
end;
procedure TDADataTableRules.OnAfterDataRequestCall(DataTable: TDADataTable;
Request: TDARemoteRequest);
begin
end;
procedure TDADataTableRules.OnAfterDataUpdateCall(DataTable: TDADataTable;
Request: TDARemoteRequest);
begin
end;
procedure TDADataTableRules.OnAfterMergeDelta(DataTable: TDADataTable);
begin
end;
procedure TDADataTableRules.OnAfterSchemaCall(DataTable: TDADataTable;
Request: TDARemoteRequest);
begin
end;
procedure TDADataTableRules.OnAfterScriptCall(DataTable: TDADataTable;
Request: TDARemoteRequest);
begin
end;
procedure TDADataTableRules.OnBeforeApplyUpdates(DataTable: TDADataTable;
const Delta: IDADelta);
begin
end;
procedure TDADataTableRules.OnBeforeDataRequestCall(
DataTable: TDADataTable; Request: TDARemoteRequest);
begin
end;
procedure TDADataTableRules.OnBeforeDataUpdateCall(DataTable: TDADataTable;
Request: TDARemoteRequest);
begin
end;
procedure TDADataTableRules.OnBeforeMergeDelta(DataTable: TDADataTable);
begin
end;
procedure TDADataTableRules.OnBeforeSchemaCall(DataTable: TDADataTable;
Request: TDARemoteRequest);
begin
end;
procedure TDADataTableRules.OnBeforeScriptCall(DataTable: TDADataTable;
Request: TDARemoteRequest);
begin
end;
procedure TDADataTableRules.OnReceiveDataStream(DataTable: TDADataTable;
Stream: TStream);
begin
end;
{ TDAFieldRules }
constructor TDAFieldRules.Create(aField : TDAField; aDataTable : TDADataTable);
begin
inherited Create;
fDataTable := aDataTable;
fField := aField;
fField.OnValidate := OnValidate;
fField.OnChange := OnChange;
Attach(fDataTable);
end;
destructor TDAFieldRules.Destroy;
begin
Detach(fDataTable);
inherited;
end;
procedure TDAFieldRules.Attach(aDataTable: TDADataTable);
begin
end;
procedure TDAFieldRules.Detach(aDataTable: TDADataTable);
begin
end;
procedure TDAFieldRules.OnChange(Sender: TDACustomField);
begin
end;
procedure TDAFieldRules.OnValidate(Sender: TDACustomField);
begin
end;
{ TDADataTableList }
constructor TDADataTableList.Create(aOwnerComponent: TComponent);
begin
inherited Create;
ScanAndAdd(aOwnerComponent);
end;
function TDADataTableList.Add(aDataTable: TDADataTable): integer;
begin
result := inherited Add(aDataTable);
end;
function TDADataTableList.GetItems(Index: integer): TDADataTable;
begin
result := TDADataTable(inherited Items[Index]);
end;
procedure TDADataTableList.Remove(aDataTable: TDADataTable);
begin
inherited Remove(aDataTable);
end;
function TDADataTableList.ScanAndAdd(aOwnerComponent: TComponent): integer;
var i : integer;
begin
result := 0;
with aOwnerComponent do begin
for i := 0 to (Count-1) do
if (Components[i] is TDADataTable) then begin
Add(TDADataTable(Components[i]));
Inc(result);
end;
end;
end;
function TDADataTableList.GetPendingChangeCount: integer;
var i : integer;
begin
result := 0;
for i := 0 to (Count-1) do
if Items[i].Active and Items[i].LogChanges
then Inc(result, Items[i].Delta.Count);
end;
{ TDABaseRemoteDataAdapter }
function TDABaseRemoteDataAdapter.Get_GetDataCall: TDARemoteRequest;
begin
result := nil;
end;
function TDABaseRemoteDataAdapter.Get_GetSchemaCall: TDARemoteRequest;
begin
result := nil;
end;
function TDABaseRemoteDataAdapter.Get_GetScriptsCall: TDARemoteRequest;
begin
result := nil;
end;
function TDABaseRemoteDataAdapter.Get_UpdateDataCall: TDARemoteRequest;
begin
result := nil;
end;
initialization
RegisterExceptionClass(EDABizValidationException);
_bizfields := TStringList.Create;
_bizfields.Sorted := TRUE;
_bizdatatables := TStringList.Create;
_bizdatatables.Sorted := TRUE;
finalization
UnregisterExceptionClass(EDABizValidationException);
_bizdatatables.Free;
_bizfields.Free;
end.