Question

I have a master/detail ClientDataSet as follows (these are created/populated at run-time and populated with data returned from an API call, no database connection):

Services:
  ID
  Name
  BasePrice
  etc.

AddOns:
  Selected
  ID
  ServiceID
  Name
  Quantity
  UnitCost
  TotalCost
  etc.

I display the Services as a dropdown field that then populates a grid with the available add-ons for that service. The field 'TotalCost' is a calculated field displayed in the grid in its own column. The 'Selected' field is used to track a checkbox shown in the grid to indicate the customer wants that particular add-on.

This all works as expected. I now need to calculate the total cost of the service plus any add-ons. The cost of the service I am able to retrieve using:

ClientDataSetServices.FieldByName('BasePrice').Value

However, I am unable to retrieve the TotalCost from each selected add-on. I thought I could use an Aggregate field but in my searches I found that this is not doable using a master/detail setup. I also tried to simply iterate through the details ClientsDataSet as follows:

  (within the CalcFields method of the details ClientDataSet)
  // Add parts to parts cost
  grdMain.DataSource.DataSet.First;
  while not grdMain.DataSource.DataSet.Eof do begin

    if (grdMain.DataSource.DataSet.FieldByName('Selected').Value) then begin
      FPartsCost := FPartsCost +      
                    grdMain.DataSource.DataSet.FieldByName('TotalPrice').Value;
    end;

    grdMain.DataSource.DataSet.Next;
  end;

But this causes an infinite loop. When I debug this portion of code I find that the ...DataSet.First is calling CalcFields (or something else that is in turn calling CalcFields).

How can I iterate over the DataSet of selected add-ons to calculate the total costs dynamically (whenever a selection or quantity changes)?

--EDIT--

I tried to setup an Aggregate on the details table as follows:

  • Added TAggregate 'AggregatePrice'
  • Set the fields as follows: Active - True Name - AggregatePrice' Expression - SUM(TotalPrice) GroupingLevel - 1 IndexName - ServiceId Visible - True

When I run this I get the error message "Field 'TotalPrice' is not the correct type of calcualted field to be used in an aggregate, use an internalcalc"

Was it helpful?

Solution

After your edit the answer seems obvious: use an InternalCalc field instead of a simple CalcField!

The calculation is still done inside the OnCalcField, but you have to check the TDataset.State for dsInternalCalc.

This is necessary because the aggregates are calculated after dsInternalCalc but before dsCalcFields state.

As a side note, an InternalCalc field can be used for an index, but a simple CalcField cannot.

OTHER TIPS

One way would be to use a Cloned Cursor for the details - a copy of the dataset that is kept in synch with the contents of its source, but which can be navigated independently.

eg.

CopyCDS.CloneCursor(OriginalCDS,False); // check params in help to see options
CopyCDS.First;
while not CopyCDS.EOF do
  begin
  // do stuff to calculate what you need
  CopyCDS.Next;
  end;

Bear in mind that a cloned cursor will not have any calculated fields or any of the events associated with the original, so you'll need to set those up again if needed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top