mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-10 10:09:21 +02:00
* Support for Master-Detail relations in data manager
git-svn-id: trunk@38625 -
This commit is contained in:
parent
1497b64804
commit
492dc01483
@ -20,6 +20,10 @@ Type
|
||||
// Override this to return a dataset which is owned by AOwner, and configured by AConfig.
|
||||
// The dataset must not be opened.
|
||||
Function CreateDataset(AOwner : TComponent; AConfig : TJSONObject) : TDataset; virtual; abstract;
|
||||
// By default, master-detail is not possible. Let this return 'True' indicate that a dataset allows master-detail.
|
||||
Class Function AllowMasterDetail : Boolean; virtual;
|
||||
// This is called to set the master dataset on Detail
|
||||
Class Procedure SetMasterDataset(ADetail,AMaster : TDataset); virtual;
|
||||
// Check if the configuration is valid. Return a string that describes the error(s)
|
||||
// If the return is an empty string, the data designer will not close.
|
||||
Class Function CheckConfig(AConfig : TJSONObject) : String; virtual;
|
||||
@ -36,12 +40,14 @@ Type
|
||||
private
|
||||
FConfig: TJSONObject;
|
||||
FDataType: String;
|
||||
FMaster: String;
|
||||
FName: String;
|
||||
FReportData: TFPReportDatasetData;
|
||||
FRunReportDataItem: TFPReportDataItem;
|
||||
function GetJSONConfig: TJSONStringType;
|
||||
procedure SetConfig(AValue: TJSONObject);
|
||||
procedure SetJSONConfig(AValue: TJSONStringType);
|
||||
procedure SetMaster(AValue: String);
|
||||
procedure SetName(AValue: String);
|
||||
Protected
|
||||
// To hold temporary references
|
||||
@ -63,6 +69,7 @@ Type
|
||||
Published
|
||||
property Name : String Read FName Write SetName;
|
||||
Property DataType : String Read FDataType Write FDataType;
|
||||
property Master : String Read FMaster Write SetMaster;
|
||||
Property JSONConfig : TJSONStringType Read GetJSONConfig Write SetJSONConfig;
|
||||
end;
|
||||
|
||||
@ -75,6 +82,7 @@ Type
|
||||
Public
|
||||
Function IndexOfRunData(aData : TFPReportDatasetData) : integer;
|
||||
Function IndexOfName(const aName : String): Integer;
|
||||
Procedure CheckCircularReference(aMasterName : String; aItem : TFPReportDataDefinitionItem);
|
||||
Function FindDataByName(const aName : String): TFPReportDataDefinitionItem;
|
||||
Function AddData(const aName : String) : TFPReportDataDefinitionItem;
|
||||
Procedure SaveToJSON(O : TJSONObject);
|
||||
@ -148,7 +156,10 @@ Resourcestring
|
||||
SErrInvalidDataType = 'Invalid data type: "%s"';
|
||||
SErrInvalidJSONConfig = '%s: Invalid JSON Configuration';
|
||||
SErrUnknownDataType = 'Unknown report data type: %s';
|
||||
|
||||
SErrNoMasterDetailSupport = 'No master-detail support for class "%s"';
|
||||
SErrOpeningDataset = 'Error opening data "%s" : Exception %s with message %s';
|
||||
SErrInvalidDatasourceName = 'Invalid data source name : "%s"';
|
||||
SErrCircularReference = 'Invalid master data source "%s", circular references not allowed.';
|
||||
|
||||
implementation
|
||||
|
||||
@ -333,6 +344,7 @@ Var
|
||||
I : Integer;
|
||||
|
||||
begin
|
||||
aReport.SaveDataToNames;
|
||||
For I:=0 to DataDefinitions.Count-1 do
|
||||
begin
|
||||
DD:=DataDefinitions[i];
|
||||
@ -364,16 +376,17 @@ procedure TFPCustomReportDataManager.ApplyToReport(aReport : TFPReport; Errors:
|
||||
|
||||
Var
|
||||
I : Integer;
|
||||
DesignD : TFPReportDataDefinitionItem;
|
||||
MasterD,DesignD : TFPReportDataDefinitionItem;
|
||||
DatasetD : TFPReportDatasetData;
|
||||
H : TFPReportDataHandler;
|
||||
L : TFPList;
|
||||
P : TComponent;
|
||||
DDS,MDS : TDataset;
|
||||
|
||||
begin
|
||||
RemoveFromReport(aReport);
|
||||
P:=GetDatasetParent;
|
||||
aReport.SaveDataToNames;
|
||||
aReport.ReportData.Clear;
|
||||
// Create all datasets
|
||||
For I:=0 to DataDefinitions.Count-1 do
|
||||
begin
|
||||
DesignD:=DataDefinitions[i];
|
||||
@ -386,7 +399,7 @@ begin
|
||||
except
|
||||
On E : Exception do
|
||||
If Assigned(Errors) then
|
||||
Errors.Add(Format('Error opening data "%s" : Exception %s with message %s',[DesignD.Name,E.ClassName,E.Message]))
|
||||
Errors.Add(Format(SErrOpeningDataset, [DesignD.Name, E.ClassName, E.Message]))
|
||||
else
|
||||
Raise;
|
||||
end;
|
||||
@ -395,6 +408,19 @@ begin
|
||||
DatasetD.StartDesigning; // set designing flag, or OI will not show reference to it.
|
||||
DesignD.RunReportDataItem:=aReport.ReportData.AddReportData(DatasetD);
|
||||
end;
|
||||
// Set master-detail relations
|
||||
For I:=0 to DataDefinitions.Count-1 do
|
||||
begin
|
||||
DesignD:=DataDefinitions[i];
|
||||
if (DesignD.Master<>'') then
|
||||
begin
|
||||
H:=TFPCustomReportDataManager.GetTypeHandler(DesignD.DataType);
|
||||
MasterD:=DataDefinitions.FindDataByName(DesignD.Master);
|
||||
DDS:=(DesignD.RunReportDataItem.Data as TFPReportDatasetData).DataSet;
|
||||
MDS:=(MasterD.RunReportDataItem.Data as TFPReportDatasetData).DataSet;
|
||||
H.SetMasterDataset(DDS,MDS);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TFPCustomReportDataManager.GetRegisteredTypes(AList: Tstrings): Integer;
|
||||
@ -486,6 +512,24 @@ begin
|
||||
Dec(Result);
|
||||
end;
|
||||
|
||||
procedure TFPReportDataDefinitions.CheckCircularReference(aMasterName: String; aItem: TFPReportDataDefinitionItem);
|
||||
|
||||
Var
|
||||
DD : TFPReportDataDefinitionItem;
|
||||
|
||||
begin
|
||||
While (aMasterName<>'') do
|
||||
begin
|
||||
DD:=FindDataByName(aMasterName);
|
||||
if (DD=Nil) then
|
||||
raise EReportDataError.CreateFmt(SErrInvalidDatasourceName, [aMasterName]);
|
||||
If (DD=aItem) then
|
||||
raise EReportDataError.CreateFmt(SErrCircularReference, [aMasterName]);
|
||||
aMasterName:=DD.Master;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
function TFPReportDataDefinitions.FindDataByName(const aName: String): TFPReportDataDefinitionItem;
|
||||
|
||||
var
|
||||
@ -503,7 +547,7 @@ function TFPReportDataDefinitions.AddData(const aName: String): TFPReportDataDef
|
||||
|
||||
begin
|
||||
if (IndexOfName(aName)<>-1) then
|
||||
raise EReportError.CreateFmt(SErrDuplicateData, [aName]);
|
||||
raise EReportDataError.CreateFmt(SErrDuplicateData, [aName]);
|
||||
Result:=add as TFPReportDataDefinitionItem;
|
||||
Result.Name:=aName;
|
||||
end;
|
||||
@ -562,6 +606,15 @@ begin
|
||||
TFPCustomReportDataManager.RegisterConfigFrameClass(DataType,aClass);
|
||||
end;
|
||||
|
||||
class function TFPReportDataHandler.AllowMasterDetail: Boolean;
|
||||
begin
|
||||
Result:=False;
|
||||
end;
|
||||
|
||||
Class procedure TFPReportDataHandler.SetMasterDataset(ADetail, AMaster: TDataset);
|
||||
begin
|
||||
Raise EReportDataError.CreateFmt(SErrNoMasterDetailSupport,[ADetail.ClassName]);
|
||||
end;
|
||||
|
||||
|
||||
class function TFPReportDataHandler.CheckConfig(AConfig: TJSONObject): String;
|
||||
@ -612,6 +665,12 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFPReportDataDefinitionItem.SetMaster(AValue: String);
|
||||
begin
|
||||
if FMaster=AValue then Exit;
|
||||
FMaster:=AValue;
|
||||
end;
|
||||
|
||||
procedure TFPReportDataDefinitionItem.SetName(AValue: String);
|
||||
begin
|
||||
if FName=AValue then Exit;
|
||||
@ -638,6 +697,7 @@ begin
|
||||
Config:=D.Config;
|
||||
Name:=D.Name;
|
||||
DataType:=D.DataType;
|
||||
Master:=D.Master;
|
||||
end
|
||||
else
|
||||
inherited Assign(Source);
|
||||
@ -648,6 +708,7 @@ begin
|
||||
O.Add('name',Name);
|
||||
O.Add('type',DataType);
|
||||
O.Add('config',Config.Clone);
|
||||
O.Add('master',Master);
|
||||
end;
|
||||
|
||||
procedure TFPReportDataDefinitionItem.LoadFromJSON(O: TJSONObject);
|
||||
@ -661,6 +722,7 @@ begin
|
||||
C:=O.Get('config',TJSONObject(Nil));
|
||||
if Assigned(C) then
|
||||
Config:=C;
|
||||
Master:=O.Get('master','');
|
||||
end;
|
||||
|
||||
function TFPReportDataDefinitionItem.Clone(aNewName: String): TFPReportDataDefinitionItem;
|
||||
|
@ -68,11 +68,15 @@ Type
|
||||
end;
|
||||
|
||||
|
||||
{ TSQLDBReportDataHandler }
|
||||
|
||||
TSQLDBReportDataHandler = Class(TFPReportDataHandler)
|
||||
Function CreateDataset(AOwner : TComponent; AConfig : TJSONObject) : TDataset; override;
|
||||
Class Function CheckConfig(AConfig: TJSONObject): String; override;
|
||||
Class Function DataType : String; override;
|
||||
Class Function DataTypeDescription : String; override;
|
||||
Class Function AllowMasterDetail: Boolean; override;
|
||||
Class Procedure SetMasterDataset(ADetail, AMaster: TDataset); override;
|
||||
end;
|
||||
|
||||
|
||||
@ -262,6 +266,28 @@ begin
|
||||
Result:='SQL Database server';
|
||||
end;
|
||||
|
||||
class function TSQLDBReportDataHandler.AllowMasterDetail: Boolean;
|
||||
begin
|
||||
Result:=True;
|
||||
end;
|
||||
|
||||
class procedure TSQLDBReportDataHandler.SetMasterDataset(ADetail, AMaster: TDataset);
|
||||
|
||||
Var
|
||||
Q : TSQLQuery;
|
||||
DS : TDatasource;
|
||||
|
||||
begin
|
||||
Q:=(ADetail as TSQLQuery);
|
||||
DS:=Q.DataSource;
|
||||
if DS=Nil then
|
||||
begin
|
||||
DS:=TDatasource.Create(Q);
|
||||
Q.Datasource:=DS;
|
||||
end;
|
||||
DS.Dataset:=AMaster;
|
||||
end;
|
||||
|
||||
initialization
|
||||
TSQLDBReportDataHandler.RegisterHandler;
|
||||
TFPReportConnector.Init;
|
||||
|
Loading…
Reference in New Issue
Block a user