Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Firedac - How to copy TFDQuery structure (fields and definitions) ?


This question is answered.


Permlink Replies: 11 - Last Post: Nov 9, 2017 10:06 AM Last Post By: Jeff Overcash (...
Jose Silva

Posts: 20
Registered: 11/1/11
Firedac - How to copy TFDQuery structure (fields and definitions) ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 2, 2017 5:42 PM
Hi guys ,

I'm coding in Delphi Tokyo and I had a difficult to find a method for copying TFDQuery fields definition to another TFDQuery.
My Scenary :
1- I've defined at design-time, a TFDQueryA in a datamodule and configured all fields properties like position, display label, display format, using Filds Editor
2 - I have a TDBGrid that points to a datasource which is linked to this TFDQuery dataset , therefore it will assume all field definitions for the DBGridColoumns

What I Need
1 - At runtime I'll create other TFDQuery, one for each form instance opened, with same SQL command as the original TFDQueryA, in order to populate the DBGrid.
2 - I need to have exactly the same field configurations I've defined for TFDQueryA for these recently created TFDQueryB, C, D etc... I need to keep fields display labels, position, display format as defined previously in TFDQueryA Fields Editor.

What I've tried
1 - I've tried Assign command : TFDQueryB.Assign(Dtmodule.TFAQueryA) ==> got an Runtime Error : Cannot assign a TFDQuery to a TFDQuery
2- FieldDefs Assign command : TFDQueryB.FieldDefs.Assign(Dtmodule.TFAQueryA.FieldDefs) and also tried
3 - command TFDQueryB.FieldDefs := Dtmodule.TFAQueryA.FieldDefs in those 2 cases (2 and 3) I obseverd that the field definitions were assigned to te new TFDQueryB , but as soon as I run the query TFDQueryB.Open and populated DBGrid1 , all fields appeared withoud formatting and in different order. It seems to me that Open dataset has overlaped the Field definitions !

Concluding, the probelm I need to solve is : how to instantiate a new TFDQuery with identical structure (SQL, parameters, Field Definitions) as the existing one created at design-time ?

I appreciate your attention and valuable support.

Thanks in advance.
Jose

Edited by: Jose Silva on Nov 2, 2017 5:43 PM
Dmitry Vavilov

Posts: 29
Registered: 9/23/17
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 3, 2017 4:48 AM   in response to: Jose Silva in response to: Jose Silva
Have you tried CopyDataSet metod?

Example
// copies dataset structure and all records
FDQuery2.CopyDataSet(FDQuery1, [coStructure, coRestart, coAppend]);
Jose Silva

Posts: 20
Registered: 11/1/11
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 3, 2017 5:21 AM   in response to: Dmitry Vavilov in response to: Dmitry Vavilov
Yes, I've tried this before , unsing only the parameter [coStructure], once I want only the structure and not all records. But I also tried with all parameters and in each case I've got an error : Comand Text must not be empty. See my code below :

...
begin
vconnection := TFDConnection.Create(nil);
vconnection.Assign(Dtmodule.FDConGrafico);

vdataset := TFDQuery.Create(nil);
vdataset.Connection := vconnection;

vdataset.CopyDataSet(Dtmodule.FDQueryDados, [coStructure,coRestart, coAppend]);

// ==> I got an error : [FireDAC][Phys][Ora]-306. Command text must not be empty

vdataset.sql := Dtmodule.FDQueryDados.sql; // I put these to lines trying avoid the error, but it persisted
vdataset.params := Dtmodule.FDQueryDados.Params;

vdatasource := Tdatasource.create(nil);
vdatasource.DataSet := vdataset;

dbgrid1.DataSource := vdatasource;

vdataset.close;
vdataset.Params[0].Asinteger := strtoint(edit1.Text);
vdataset.Params[1].Asinteger := strtoint(edit2.Text);
vdataset.Open;

end;

Thanks, anyway !

Dmitry Vavilov wrote:
Have you tried CopyDataSet metod?

Example
// copies dataset structure and all records
FDQuery2.CopyDataSet(FDQuery1, [coStructure, coRestart, coAppend]);

Edited by: Jose Silva on Nov 3, 2017 5:22 AM

Edited by: Jose Silva on Nov 3, 2017 5:30 AM
Dmitry Vavilov

Posts: 29
Registered: 9/23/17
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ?
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 3, 2017 11:05 AM   in response to: Jose Silva in response to: Jose Silva
try the procedure:
procedure CopyStructure(ASource: TDataset; ADest: TFDQuery; AOptions: TFDCopyDataSetOptions = []);
  var
    oIndDefs: TIndexDefs;
    lHasNestedDS: Boolean;
    i: Integer;
    oFld, oSrcFld: TField;
 
    function InnerUpdateDefs(AFields: TFields; ADefs: TFieldDefs): Boolean;
    var
      i: Integer;
      oSrcFld: TField;
      j: Integer;
      oDef: TFieldDef;
      oDS: TDataSet;
    begin
      Result := False;
      for i := 0 to AFields.Count - 1 do begin
        oSrcFld := AFields[i];
        j := ADefs.IndexOf(oSrcFld.FieldName);
        if (coCalcFields in AOptions) and (oSrcFld.FieldKind <> fkData) and (j = -1) then
          ADefs.Add(oSrcFld.FieldName, oSrcFld.DataType, oSrcFld.Size)
        else begin
          if j = -1 then
            Continue;
          oDef := ADefs[j];
          if (oSrcFld.FieldKind = fkData) and (oSrcFld.DataType = ftDataSet) then begin
            oDS := TDataSetField(oSrcFld).NestedDataSet;
            oDef.ChildDefs.Assign(oDS.FieldDefs);
            InnerUpdateDefs(oDS.Fields, oDef.ChildDefs);
            Result := True;
          end
          else if (oSrcFld.FieldKind = fkData) and (oSrcFld.DataType = ftADT) then
            Result := InnerUpdateDefs(TADTField(oSrcFld).Fields, oDef.ChildDefs) or Result;
        end;
      end;
    end;
  begin
    // Recreate this dataset using ASource structure.
    ADest.Disconnect;
    if coIndexesReset in AOptions then
    begin
      ADest.IndexName := '';
      ADest.IndexFieldNames := '';
      ADest.IndexDefs.Clear;
      ADest.Indexes.Clear;
    end;
 
    if coIndexesCopy in AOptions then
    begin
      if ASource is TFDDataSet then
      begin
        ADest.IndexDefs := TFDDataSet(ASource).IndexDefs;
        ADest.Indexes := TFDDataSet(ASource).Indexes;
        ADest.IndexName := TFDDataSet(ASource).IndexName;
        ADest.IndexFieldNames := TFDDataSet(ASource).IndexFieldNames;
        ADest.IndexesActive := TFDDataSet(ASource).IndexesActive;
      end
      else
      begin
        oIndDefs := (ASource as IProviderSupportNG).PSGetIndexDefs;
        try
          if oIndDefs <> nil then
            ADest.IndexDefs := oIndDefs;
        finally
          oIndDefs.DisposeOf;
        end;
      end;
    end;
 
    if coAggregatesReset in AOptions then
      ADest.Aggregates.Clear;
 
    if (coAggregatesCopy in AOptions) and (ASource is TFDDataSet) then
    begin
      ADest.Aggregates := TFDDataSet(ASource).Aggregates;
      ADest.AggregatesActive := TFDDataSet(ASource).AggregatesActive;
    end;
 
    if coConstraintsReset in AOptions then
      ADest.Constraints.Clear;
 
    if (coConstraintsCopy in AOptions) and (ASource is TFDDataSet) then
    begin
      ADest.Constraints := TFDDataSet(ASource).Constraints;
      ADest.ConstraintsEnabled := TFDDataSet(ASource).ConstraintsEnabled;
    end;
 
    try
      ADest.FormatOptions.MaxBcdPrecision := MaxInt;
      ADest.FormatOptions.MaxBcdScale := MaxInt;
      if ASource.Active then
        ASource.FieldDefs.Update;
      ADest.FieldDefs.Assign(ASource.FieldDefs);
      lHasNestedDS := InnerUpdateDefs(ASource.Fields, ADest.FieldDefs);
      ADest.FieldDefList.Update;
      ADest.FieldDefs.Updated := True;
 
      if not lHasNestedDS then
      begin
        for i := 0 to ASource.FieldCount - 1 do
        begin
          oSrcFld := ASource.Fields[I];
          oFld := TFieldClass(oSrcFld.ClassType).Create(ADest);
          oFld.FieldName := oSrcFld.FieldName;
          oFld.DataSet := ADest;
 
          oFld.Alignment := oSrcFld.Alignment;
          oFld.AutoGenerateValue := oSrcFld.AutoGenerateValue;
          if coConstraintsCopy in AOptions then
          begin
            oFld.CustomConstraint := oSrcFld.CustomConstraint;
            oFld.ConstraintErrorMessage := oSrcFld.ConstraintErrorMessage;
            oFld.ImportedConstraint := oSrcFld.ImportedConstraint;
          end;
          oFld.DefaultExpression := oSrcFld.DefaultExpression;
          oFld.DisplayLabel := oSrcFld.DisplayLabel;
          oFld.DisplayWidth := oSrcFld.DisplayWidth;
          oFld.EditMask := oSrcFld.EditMask;
          oFld.FieldKind := oSrcFld.FieldKind;
          oFld.KeyFields := oSrcFld.KeyFields;
          oFld.LookupCache := oSrcFld.LookupCache;
          oFld.LookupDataSet := oSrcFld.LookupDataSet;
          oFld.LookupKeyFields := oSrcFld.LookupKeyFields;
          oFld.LookupResultField := oSrcFld.LookupResultField;
          oFld.Origin := oSrcFld.Origin;
          oFld.ProviderFlags := oSrcFld.ProviderFlags;
          oFld.ReadOnly := oSrcFld.ReadOnly;
          oFld.Required := oSrcFld.Required;
          oFld.Size := oSrcFld.Size;
          oFld.Visible := oSrcFld.Visible;
          if oSrcFld.DataType = ftBLOB then
           TBlobField(oFld).BlobType := ftBlob;
 
         if oFld is TFloatField then
           TFloatField(oFld).Precision := TFloatField(oSrcFld).Precision else
         if oFld is TBCDField then
           TBCDField(oFld).Precision := TBCDField(oSrcFld).Precision else
         if oFld is TFMTBCDField then
           TFMTBCDField(oFld).Precision := TFMTBCDField(oSrcFld).Precision else
         if oFld is TSingleField then
           TSingleField(oFld).Precision := TSingleField(oSrcFld).Precision else
         if oFld is TExtendedField then
           TExtendedField(oFld).Precision := TExtendedField(oSrcFld).Precision else
         if oFld is TAggregateField then
           TAggregateField(oFld).Precision := TAggregateField(oSrcFld).Precision;
 
          if [coAppend, coEdit, coRefresh] * AOptions <> [] then
          begin
            if oFld is TFDAutoIncField then
              TFDAutoIncField(oFld).IdentityInsert := True;
            oFld.ReadOnly := False;
          end;
        end;
 
        for i := 0 to ASource.FieldCount - 1 do
        begin
          oSrcFld := ASource.Fields[i];
          oFld := ADest.FindField(oSrcFld.FieldName);
          if oFld <> nil then
            oFld.Index := oSrcFld.Index;
        end;
      end;
    finally
      ADest.Fields.LifeCycles := [lcAutomatic];
    end;
  end;


Example
 
  FDQ := TFDQuery.Create(nil);
  CopyStructure(FDQuery1, FDQ);
Jose Silva

Posts: 20
Registered: 11/1/11
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 3, 2017 12:40 PM   in response to: Dmitry Vavilov in response to: Dmitry Vavilov
Dmitry

thanks a lot for your attention and eforts in providing this code. To be honest, I'll take some time to understand and test this portion of code, once I'm beginner in Delphi. I'll study and test it.

While I was waiting for a answer, I've checked some other alternatives for having a copy of the dataset. I found some tips regarding to instantiate the datamodule and some other strategies to split the codes in different layers of responsibility.

Could you tell me how to instantiate the datamodule, in order to achieve the my goal as follows : a single formA will be opened several times (several instances) and in each of this form instancies I have a call to a FDQuery using a especific datasource.

I appreciate your help on this !

Thanks.

Dmitry Vavilov wrote:
try the procedure:
procedure CopyStructure(ASource: TDataset; ADest: TFDQuery; AOptions: TFDCopyDataSetOptions = []);
  var
    oIndDefs: TIndexDefs;
    lHasNestedDS: Boolean;
    i: Integer;
    oFld, oSrcFld: TField;
 
    function InnerUpdateDefs(AFields: TFields; ADefs: TFieldDefs): Boolean;
    var
      i: Integer;
      oSrcFld: TField;
      j: Integer;
      oDef: TFieldDef;
      oDS: TDataSet;
    begin
      Result := False;
      for i := 0 to AFields.Count - 1 do begin
        oSrcFld := AFields[i];
        j := ADefs.IndexOf(oSrcFld.FieldName);
        if (coCalcFields in AOptions) and (oSrcFld.FieldKind <> fkData) and (j = -1) then
          ADefs.Add(oSrcFld.FieldName, oSrcFld.DataType, oSrcFld.Size)
        else begin
          if j = -1 then
            Continue;
          oDef := ADefs[j];
          if (oSrcFld.FieldKind = fkData) and (oSrcFld.DataType = ftDataSet) then begin
            oDS := TDataSetField(oSrcFld).NestedDataSet;
            oDef.ChildDefs.Assign(oDS.FieldDefs);
            InnerUpdateDefs(oDS.Fields, oDef.ChildDefs);
            Result := True;
          end
          else if (oSrcFld.FieldKind = fkData) and (oSrcFld.DataType = ftADT) then
            Result := InnerUpdateDefs(TADTField(oSrcFld).Fields, oDef.ChildDefs) or Result;
        end;
      end;
    end;
  begin
    // Recreate this dataset using ASource structure.
    ADest.Disconnect;
    if coIndexesReset in AOptions then
    begin
      ADest.IndexName := '';
      ADest.IndexFieldNames := '';
      ADest.IndexDefs.Clear;
      ADest.Indexes.Clear;
    end;
 
    if coIndexesCopy in AOptions then
    begin
      if ASource is TFDDataSet then
      begin
        ADest.IndexDefs := TFDDataSet(ASource).IndexDefs;
        ADest.Indexes := TFDDataSet(ASource).Indexes;
        ADest.IndexName := TFDDataSet(ASource).IndexName;
        ADest.IndexFieldNames := TFDDataSet(ASource).IndexFieldNames;
        ADest.IndexesActive := TFDDataSet(ASource).IndexesActive;
      end
      else
      begin
        oIndDefs := (ASource as IProviderSupportNG).PSGetIndexDefs;
        try
          if oIndDefs <> nil then
            ADest.IndexDefs := oIndDefs;
        finally
          oIndDefs.DisposeOf;
        end;
      end;
    end;
 
    if coAggregatesReset in AOptions then
      ADest.Aggregates.Clear;
 
    if (coAggregatesCopy in AOptions) and (ASource is TFDDataSet) then
    begin
      ADest.Aggregates := TFDDataSet(ASource).Aggregates;
      ADest.AggregatesActive := TFDDataSet(ASource).AggregatesActive;
    end;
 
    if coConstraintsReset in AOptions then
      ADest.Constraints.Clear;
 
    if (coConstraintsCopy in AOptions) and (ASource is TFDDataSet) then
    begin
      ADest.Constraints := TFDDataSet(ASource).Constraints;
      ADest.ConstraintsEnabled := TFDDataSet(ASource).ConstraintsEnabled;
    end;
 
    try
      ADest.FormatOptions.MaxBcdPrecision := MaxInt;
      ADest.FormatOptions.MaxBcdScale := MaxInt;
      if ASource.Active then
        ASource.FieldDefs.Update;
      ADest.FieldDefs.Assign(ASource.FieldDefs);
      lHasNestedDS := InnerUpdateDefs(ASource.Fields, ADest.FieldDefs);
      ADest.FieldDefList.Update;
      ADest.FieldDefs.Updated := True;
 
      if not lHasNestedDS then
      begin
        for i := 0 to ASource.FieldCount - 1 do
        begin
          oSrcFld := ASource.Fields[I];
          oFld := TFieldClass(oSrcFld.ClassType).Create(ADest);
          oFld.FieldName := oSrcFld.FieldName;
          oFld.DataSet := ADest;
 
          oFld.Alignment := oSrcFld.Alignment;
          oFld.AutoGenerateValue := oSrcFld.AutoGenerateValue;
          if coConstraintsCopy in AOptions then
          begin
            oFld.CustomConstraint := oSrcFld.CustomConstraint;
            oFld.ConstraintErrorMessage := oSrcFld.ConstraintErrorMessage;
            oFld.ImportedConstraint := oSrcFld.ImportedConstraint;
          end;
          oFld.DefaultExpression := oSrcFld.DefaultExpression;
          oFld.DisplayLabel := oSrcFld.DisplayLabel;
          oFld.DisplayWidth := oSrcFld.DisplayWidth;
          oFld.EditMask := oSrcFld.EditMask;
          oFld.FieldKind := oSrcFld.FieldKind;
          oFld.KeyFields := oSrcFld.KeyFields;
          oFld.LookupCache := oSrcFld.LookupCache;
          oFld.LookupDataSet := oSrcFld.LookupDataSet;
          oFld.LookupKeyFields := oSrcFld.LookupKeyFields;
          oFld.LookupResultField := oSrcFld.LookupResultField;
          oFld.Origin := oSrcFld.Origin;
          oFld.ProviderFlags := oSrcFld.ProviderFlags;
          oFld.ReadOnly := oSrcFld.ReadOnly;
          oFld.Required := oSrcFld.Required;
          oFld.Size := oSrcFld.Size;
          oFld.Visible := oSrcFld.Visible;
          if oSrcFld.DataType = ftBLOB then
           TBlobField(oFld).BlobType := ftBlob;
 
         if oFld is TFloatField then
           TFloatField(oFld).Precision := TFloatField(oSrcFld).Precision else
         if oFld is TBCDField then
           TBCDField(oFld).Precision := TBCDField(oSrcFld).Precision else
         if oFld is TFMTBCDField then
           TFMTBCDField(oFld).Precision := TFMTBCDField(oSrcFld).Precision else
         if oFld is TSingleField then
           TSingleField(oFld).Precision := TSingleField(oSrcFld).Precision else
         if oFld is TExtendedField then
           TExtendedField(oFld).Precision := TExtendedField(oSrcFld).Precision else
         if oFld is TAggregateField then
           TAggregateField(oFld).Precision := TAggregateField(oSrcFld).Precision;
 
          if [coAppend, coEdit, coRefresh] * AOptions <> [] then
          begin
            if oFld is TFDAutoIncField then
              TFDAutoIncField(oFld).IdentityInsert := True;
            oFld.ReadOnly := False;
          end;
        end;
 
        for i := 0 to ASource.FieldCount - 1 do
        begin
          oSrcFld := ASource.Fields[i];
          oFld := ADest.FindField(oSrcFld.FieldName);
          if oFld <> nil then
            oFld.Index := oSrcFld.Index;
        end;
      end;
    finally
      ADest.Fields.LifeCycles := [lcAutomatic];
    end;
  end;


Example
 
  FDQ := TFDQuery.Create(nil);
  CopyStructure(FDQuery1, FDQ);
Jeff Overcash (...

Posts: 1,529
Registered: 9/23/99
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ?
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 3, 2017 1:25 PM   in response to: Jose Silva in response to: Jose Silva
Jose Silva wrote:
Dmitry

thanks a lot for your attention and eforts in providing this code. To be honest, I'll take some time to understand and test this portion of code, once I'm beginner in Delphi. I'll study and test it.

While I was waiting for a answer, I've checked some other alternatives for having a copy of the dataset. I found some tips regarding to instantiate the datamodule and some other strategies to split the codes in different layers of responsibility.

Could you tell me how to instantiate the datamodule, in order to achieve the my goal as follows : a single formA will be opened several times (several instances) and in each of this form instancies I have a call to a FDQuery using a especific datasource.

I appreciate your help on this !

Thanks.

Put all your Database stuff in a Datamodule (Datasources can stay on your form
linked to the dataset in the DM). Do not have that DM auto created (which means
your connection layer stuff probably should be in its own DM that is auto
created and your DM links to the connection that way). Override the Form's
constructor. In it you basically do

1. Create an instance of the DM assigning it to a local form variable (you can
let the form own it for easy cleanup)

2. Call inherited

3. Change the name of your DM to something else

The streaming lookup looks up on the linked object's name. So it is important
that when inherited is called there is only one object with the design time name
instantiated. That is why you do not auto create it and you also change the
name once the form streaming is finished.

--
Jeff Overcash (TeamB)
(Please do not email me directly unless asked. Thank You)
Learning is finding out what you already know. Doing is demonstrating that you
know it. Teaching is reminding others that they know it as well as you. We are
all leaners, doers, teachers. (R Bach)
Jose Silva

Posts: 20
Registered: 11/1/11
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 3, 2017 2:20 PM   in response to: Jeff Overcash (... in response to: Jeff Overcash (...
Jeff, thanks for the directions!

I search for examples for instantiate a datamodule , but I couldn't find a clear one. Is it possibile you , or someone on this forum, post a sample code on how to implement those 3 steps ?

I apologize for my low knowledge of Delphi , but would you kindly explain what is the "streeming lookup" ?

Thank you !

Jeff Overcash (TeamB) wrote:
Jose Silva wrote:
Dmitry

thanks a lot for your attention and eforts in providing this code. To be honest, I'll take some time to understand and test this portion of code, once I'm beginner in Delphi. I'll study and test it.

While I was waiting for a answer, I've checked some other alternatives for having a copy of the dataset. I found some tips regarding to instantiate the datamodule and some other strategies to split the codes in different layers of responsibility.

Could you tell me how to instantiate the datamodule, in order to achieve the my goal as follows : a single formA will be opened several times (several instances) and in each of this form instancies I have a call to a FDQuery using a especific datasource.

I appreciate your help on this !

Thanks.

Put all your Database stuff in a Datamodule (Datasources can stay on your form
linked to the dataset in the DM). Do not have that DM auto created (which means
your connection layer stuff probably should be in its own DM that is auto
created and your DM links to the connection that way). Override the Form's
constructor. In it you basically do

1. Create an instance of the DM assigning it to a local form variable (you can
let the form own it for easy cleanup)

2. Call inherited

3. Change the name of your DM to something else

The streaming lookup looks up on the linked object's name. So it is important
that when inherited is called there is only one object with the design time name
instantiated. That is why you do not auto create it and you also change the
name once the form streaming is finished.

--
Jeff Overcash (TeamB)
(Please do not email me directly unless asked. Thank You)
Learning is finding out what you already know. Doing is demonstrating that you
know it. Teaching is reminding others that they know it as well as you. We are
all leaners, doers, teachers. (R Bach)
Jeff Overcash (...

Posts: 1,529
Registered: 9/23/99
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ?
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 3, 2017 9:56 PM   in response to: Jose Silva in response to: Jose Silva
Jose Silva wrote:
Jeff, thanks for the directions!

I search for examples for instantiate a datamodule , but I couldn't find a clear one. Is it possibile you , or someone on this forum, post a sample code on how to implement those 3 steps ?

dm := TMyDatamodule.Create(self);

where DM is a variable of type TMyDatamodule (or whatever you call your
datamodule's class) and should be a private variable in the form.

I apologize for my low knowledge of Delphi , but would you kindly explain what is the "streeming lookup" ?

Your DFM contains all the properties you set at design time. During creation
the DFM is streamed into memory and those properties set. Some properties like
for a TDataSource will be linked to a Dataset in a DataModule and will look like

Dataset=MyDataModule.Dataset1

At load time for the DFM the streaming mechanism looks for a form or Datamodule
with the name of MyDataModule. If it finds it it then verifies Dataset1 exists
in that DataModule and if both are true it makes the linkage. If either is
false is jsut silently sets the property to nil.

Since it is looking up by name, and the lookup just returns the first with that
name it is important that in normal situations that name does not exist in the
Screens global variable. You only want that name during the streaming process
for the DataModule you want linking to the form (the one you created explicitly
for this form)


Thank you !

Jeff Overcash (TeamB) wrote:
Jose Silva wrote:
Dmitry

thanks a lot for your attention and eforts in providing this code. To be honest, I'll take some time to understand and test this portion of code, once I'm beginner in Delphi. I'll study and test it.

While I was waiting for a answer, I've checked some other alternatives for having a copy of the dataset. I found some tips regarding to instantiate the datamodule and some other strategies to split the codes in different layers of responsibility.

Could you tell me how to instantiate the datamodule, in order to achieve the my goal as follows : a single formA will be opened several times (several instances) and in each of this form instancies I have a call to a FDQuery using a especific datasource.

I appreciate your help on this !

Thanks.
Put all your Database stuff in a Datamodule (Datasources can stay on your form
linked to the dataset in the DM). Do not have that DM auto created (which means
your connection layer stuff probably should be in its own DM that is auto
created and your DM links to the connection that way). Override the Form's
constructor. In it you basically do

1. Create an instance of the DM assigning it to a local form variable (you can
let the form own it for easy cleanup)

2. Call inherited

3. Change the name of your DM to something else

The streaming lookup looks up on the linked object's name. So it is important
that when inherited is called there is only one object with the design time name
instantiated. That is why you do not auto create it and you also change the
name once the form streaming is finished.

--
Jeff Overcash (TeamB)
(Please do not email me directly unless asked. Thank You)
Learning is finding out what you already know. Doing is demonstrating that you
know it. Teaching is reminding others that they know it as well as you. We are
all leaners, doers, teachers. (R Bach)

--
Jeff Overcash (TeamB)
(Please do not email me directly unless asked. Thank You)
Learning is finding out what you already know. Doing is demonstrating that you
know it. Teaching is reminding others that they know it as well as you. We are
all leaners, doers, teachers. (R Bach)

Jose Silva

Posts: 20
Registered: 11/1/11
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 8, 2017 5:15 PM   in response to: Jeff Overcash (... in response to: Jeff Overcash (...
Jeff

sorry for the delay in replying this to you, I was out a couple of days .

I test this datamodule creation and it seems it solved my problem, therefore I can now create a runtime instance of a query and datasource, having the original field definitions configured at design-time in the field editor of such query !!

Although it worked fine, some doubts have arisen about DataModules and Connection. I still appreciate your valuable comments , if you can . Please see my code below:
  Procedure  FormB.ShowUpdatedDBGrid;
  var
       Vdatamodule  : TDMResultFluxo  ;
 
  begin  
 
         Vdatamodule  := TDMResultFluxo.Create(nil);    // TDMResutFluxo is the new datamodule I create  with a FDQuery and a DataSource 
 
        DBGrid1.DataSource := vdatamodule.DtSourceResultFluxo;  
 
        Vdatamodule.FDQueryResultFluxo.Close;
        Vdatamodule.FDQueryResultFluxo.IndexFieldnames:= 'DIA'; 
        Vdatamodule.FDQueryResultFluxo.Params[0].AsInteger := Trunc(pcenario);
        Vdatamodule.FDQueryResultFluxo.Params[1].AsInteger := Trunc(psimulacao);
        Vdatamodule.FDQueryResultFluxo.Open;
 
  end;


Question 1 : Considering I'll open this FormB several times in parallel with other process running in Threads, should I put a TFDConnection
in this form OR should I only use property ConnectionName of the FDQuery ? (I read that open TFDConnection several times
consume a lot of CPU) .

Question 2 : What is the difference between place a TFDConnection in a datamodule and having all FDQueries linking to it AND
don't use a TFDConnection and setting property ConnectionName for each FDQuery in the datamodule ?

Question 3 : For the above code the datamodule variable "vdatamodule" is declared as locally at the procedure . Is that the right place or
should it be declared at private session of FormB ?

Thanks for your attention.

Jeff Overcash (TeamB) wrote:

dm := TMyDatamodule.Create(self);

where DM is a variable of type TMyDatamodule (or whatever you call your
datamodule's class) and should be a private variable in the form.


Edited by: Jose Silva on Nov 8, 2017 5:16 PM

Edited by: Jose Silva on Nov 8, 2017 5:18 PM
Lajos Juhasz

Posts: 801
Registered: 3/14/14
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 9, 2017 1:34 AM   in response to: Jose Silva in response to: Jose Silva
Jose Silva wrote:

Question 1 : Considering I'll open this FormB several times in
parallel with other process running in Threads, should I put a
TFDConnection in this form OR should I only use
property ConnectionName of the FDQuery ? (I read that open
TFDConnection several times consume a lot of
CPU) .

Where is TFDConnection definied doesn't matter. You should only pay
attention to not use Connection/Query from different threads. The
components can be accessed safely only inside the thread that creates
them.

Question 2 : What is the difference between place a TFDConnection
in a datamodule and having all FDQueries linking to it AND
don't use a TFDConnection and setting property ConnectionName for
each FDQuery in the datamodule ?

You can link a query to connection using the ConnectionName or
Connection property.


Question 3 : For the above code the datamodule variable
"vdatamodule" is declared as locally at the procedure . Is that the
right place or should it be declared at private
session of FormB ?
Thanks for your attention.

If you create the DM as a private field of a class you can access it
from every method of the class while it it's declared in a method you
can access it directly only in that method.
Jose Silva

Posts: 20
Registered: 11/1/11
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 9, 2017 6:08 AM   in response to: Lajos Juhasz in response to: Lajos Juhasz
Lajos

very clear explanations !! I got it !

Thank you so much for helping.

Jeff Overcash (...

Posts: 1,529
Registered: 9/23/99
Re: Firedac - How to copy TFDQuery structure (fields and definitions) ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 9, 2017 10:06 AM   in response to: Jose Silva in response to: Jose Silva
Jose Silva wrote:
Lajos

very clear explanations !! I got it !

Thank you so much for helping.


All three answers he gave would have been my advice too. While some client
libraries are thread safe at the connection layer (I know InterBase and Oracle
are) they are usually made thread safe by serializing access to the connection
which defeats any reasons yo thread your work as the threads would sharing a
connection would be waiting on each other. So best to follow the rule of each
thread gets its own connection.

--
Jeff Overcash (TeamB)
(Please do not email me directly unless asked. Thank You)
Learning is finding out what you already know. Doing is demonstrating that you
know it. Teaching is reminding others that they know it as well as you. We are
all leaners, doers, teachers. (R Bach)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02