1

I have been investigating what might need to be done to convert my Delphi 10.3.3 app from using TDataSource -> TClientDataSet -> TDataSetProvider -> TIBQuery to using FireDAC.

From all I read it is not a good idea to simply replace TIBQuery with TFDQuery as in TDataSource -> TClientDataSet -> TDataSetProvider -> TFDQuery. This is because TDFQuery is itself is an in-memory dataset and has all the same functionality as the client dataset. Therefore I want to remove the TClientDataSet and the TDataSetProvider components and just have a TDataSource -> TFDQuery components.

That said there is one event of the TDataSetProvider that I have not been able to find a suitable replacement for. That is the OnGetData event. In this event I do additional processing before that data is displayed to the user in the interface.

In the help file for this event it states "Occurs after a provider retrieves data but before it is sent to the client. Write an OnGetData event handler to perform any custom data processing the provider should handle before returning data to a client. The OnGetData event occurs after a provider fetches data from its dataset but before the data is sent on to the client. Using the methods of the DataSet parameter, data can be edited in the OnGetData event handler before sending it to the client dataset."

I use this event extensively in my application.

So does anyone know how I can can do this using just FireDAC FDQuery?

For example I have the following SQL statement in my query

    SELECT ACC.ACCT_ID,
       ACC.CASE_ID,
       ACCG.*,
       ATDTM.HAND_FILE_WHEN_FORMAT_IS_EFILE,
       ATDTM.ROS_CREATE_DATE,
       ATDTM.ROS_CREATE_USER,
       ATDTM.ROS_SERV_TYPE_REQ_ID,
       ATDTM.ROS_SERV_REQ_WAIT_DAYS,
       ATDTM.ROS_MODIFY_DATE,
       ATDTM.ROS_MODIFY_USER,
       ATDTM.ROS_DATE_OF_SERVICE,
       ATDTM.ROS_SERV_TYPE_REC_ID,
       ATDTM.ROS_SERVED_TO,
       ATDTM.ROS_SERVICE_BY,
       CAST(NULL AS VARCHAR(10)) AS ROS_SERVICE_BY_DESC,
       ATDTM.ROS_NO_SERV_REASON_ID,
       ATDTM.ROS_MEMO,
       GS.IMAGE_INDEX AS GARN_STATUS_IMAGE_INDEX,
       STR.SERV_TYPE_REQ_CODE AS ROS_SERV_TYPE_REQ_CODE,
       STR.DESCRIPTION AS ROS_SERV_TYPE_REQ_DESC,
       STR2.SERV_TYPE_REC_CODE AS ROS_SERV_TYPE_REC_CODE,
       STR2.DESCRIPTION AS ROS_SERV_TYPE_REC_DESC,
       NSTR.DESCRIPTION AS ROS_NO_SERV_REASON_DESC,
       CAST(NULL AS VARCHAR(50)) AS DEBTOR_FULL_NAME,
       CAST(NULL AS VARCHAR(60)) AS GARNISHEE_NAME,
       CAST(NULL AS VARCHAR(20)) AS GARN_TYPE_DESC,
       CAST(NULL AS SMALLINT) AS GARN_COMPLETED_IMAGE_INDEX,
       CAST(NULL AS INTEGER) AS TRAN_ID,
       ATDTM.ROS_COURT_FILE_STAMPED_DATE,
       CAST(NULL AS DATE) AS NMA_EMP_TERM_DATE,
       ATM.FILING_COUNTY_ID,
       C.COUNTY_CODE || C.STATE AS FILING_COUNTY_DESC
  FROM ACCT_CASE_COURT_GARNISHMENT ACCG
  JOIN ACCT_CASE_COURT ACC ON ACC.ACCT_CASE_COURT_ID = ACCG.ACCT_CASE_COURT_ID
  LEFT OUTER JOIN ACCT_TRAN_DETAIL_TASK_MERGE ATDTM ON ATDTM.ACCT_TRAN_ID = ACCG.ACCT_TRAN_ID
   AND ATDTM.ACCT_TRAN_DETAIL_ID = ACCG.ACCT_TRAN_DETAIL_ID
   AND ATDTM.ACCT_TASK_ID = ACCG.ACCT_TASK_ID
  JOIN SERVICE_TYPE_REQ STR ON STR.SERV_TYPE_REQ_ID = ATDTM.ROS_SERV_TYPE_REQ_ID
  LEFT OUTER JOIN SERVICE_TYPE_REC STR2 ON STR2.SERV_TYPE_REC_ID = ATDTM.ROS_SERV_TYPE_REC_ID
  LEFT OUTER JOIN NO_SERVICE_TYPE_REASON NSTR ON NSTR.REASON_ID = ATDTM.ROS_NO_SERV_REASON_ID
  LEFT OUTER JOIN GARN_STATUS GS ON GS.STATUS_CODE = ACCG.GARN_STATUS_CODE
  LEFT OUTER JOIN ACCT_TRAN_MASTER ATM ON ATM.ACCT_TRAN_ID = ACCG.ACCT_TRAN_ID
  LEFT OUTER JOIN COUNTY C ON C.COUNTY_ID = ATM.FILING_COUNTY_ID  
 WHERE ACC.ACCT_ID = :ACCT_ID
   AND ACC.CASE_ID = :CASE_ID
 ORDER BY ACCG.ACCT_TRAN_DETAIL_ID

And then in the TDataSetProvider.OnGetData event I have this

procedure TdtmCaseManagement.prvGarnishmentsGetData(Sender: TObject;

DataSet: TCustomClientDataSet); begin while not DataSet.Eof do begin DataSet.Edit;

  if (DataSet.FieldByName('ROS_SERV_TYPE_REC_ID').AsInteger = 1) and
     (DataSet.FieldByName('ROS_NO_SERV_REASON_ID').AsInteger = 18) then
    DataSet.FieldByName('ROS_SERV_TYPE_REC_DESC').AsString := 'No Return';

  with spsGetPersonInfo do
    begin
      if not Prepared then
        begin
          Params.Clear;
          Prepare;
        end;

      Params.ParamByName('V_PERSON_ID').AsInteger :=
        DataSet.FieldByName('PERSON_ID').AsInteger;
      Params.ParamByName('V_LAST_NAME_FIRST').AsInteger := 0;

      ExecProc;

      DataSet.FieldByName('DEBTOR_FULL_NAME').AsString :=
        Params.ParamByName('R_FULL_NAME').AsString;

      UnPrepare;
    end;

  with spsFetchGarnishee do
    begin
      if not Prepared then
        begin
          Params.Clear;
          Prepare;
        end;

      Params.ParamByName('V_GARN_TYPE').AsString :=
        DataSet.FieldByName('GARN_TYPE').AsString;
      Params.ParamByName('V_GARN_ENTITY_ID').AsInteger :=
        DataSet.FieldByName('GARN_ENTITY_ID').AsInteger;

      ExecProc;

      DataSet.FieldByName('GARNISHEE_NAME').AsString :=
        Params.ParamByName('R_GARNISHEE_NAME').AsString;

      UnPrepare;
    end;

  DataSet.Post;
  DataSet.Next;
end;

end;

STWizard
  • 31
  • 4
  • Welome to SO. Please replace your screenshots in your q by text equivalents. FireDAC does not have a direct equivalent to the DSP and OnGetData, but from a brief look it seems likely that you could replace what you do in your OnGetData with calculated fields in your FDQuery which are provided with values from a second FDQuery or similar. – MartynA Apr 29 '20 at 20:08
  • What's your goal? To move away from Interbase/Firebird or to stay with IB/FB as your database and just use FireDAC components? – LachlanG Apr 30 '20 at 04:28
  • If you are moving away from Interbase/Firebird as a first step I would keep it simple and just replace the TIBQuery with TFDQuery. You can basically disable the memory table aspects of FireDAC TFDQuery components if you set them to be unidirectional datasets. – LachlanG Apr 30 '20 at 04:32
  • @LachlanG My goal initially is to remove the IBX components completely as I use them to connect to Firebird and who know how much longer I can use them. In the beginning I was going to replace TIBQuery with TFDQuery, but after watching many webinars on FireDAC, and reading through "Delphi in Depth: FireDAC", both by Cary Jensen, I am convinced that I should be removing the TClientDataSet and TDataSetProvider components. I did reach out to Jensen Data Systems, Inc, as they state on their website that they provide Delphi training and consulting and twice I was told that he was not available. – STWizard Apr 30 '20 at 11:13
  • Well, you should see an `Edit` label to the left below the text of your q. To add code to your q, move the cursor to where you want to insert it and then do a standard copy&paste. While it is still selected in the question editor, just press Ctrl-K and that will indent it and change it to the usual code colour. – MartynA Apr 30 '20 at 11:14
  • @stwizard as you've probably discovered by now an application based on TClientDataSet/TDataSetProvider/TIBQuery is quite different from an application based on FireDAC alone. As I said earlier my first step would be just to replace the TIBQuery with TFDQuery and just use TClientDataSet/TDataSetProvider/TFDQuery for the existing code. New code I'd write with TFDQuery alone. There's no crushing need to replace the TClientDataSet/TDataSetProvider components, they'll probably never be updated but they'll be part of Delphi for many, many years to come. Replace them gradually is my advice. – LachlanG May 11 '20 at 22:58

0 Answers0