2012-04-25 4 views
2

У меня есть мастер/подробно ClientDataSet следующим образом (они создаются/заселена во время выполнения и заполняется данными возвращается из API вызова, нет подключения к базе данных):DELPHI: Master-Detail с использованием ClientDataSet и CalcFields

Services: 
    ID 
    Name 
    BasePrice 
    etc. 

AddOns: 
    Selected 
    ID 
    ServiceID 
    Name 
    Quantity 
    UnitCost 
    TotalCost 
    etc. 

Я показываю Службы как выпадающее поле, которое затем заполняет сетку доступными надстройками для этой службы. Поле «TotalCost» представляет собой вычисленное поле, отображаемое в сетке в своем столбце. Поле «Выбранные» используется для отслеживания флажка, отображаемого в сетке, чтобы указать, что клиент хочет это конкретное дополнение.

Это все работает так, как ожидалось. Теперь мне нужно рассчитать общую стоимость услуги плюс любые дополнения. Стоимость услуги я могу получить с помощью:

ClientDataSetServices.FieldByName('BasePrice').Value 

Однако я не смог получить TotalCost от каждого выбранного дополнения. Я думал, что могу использовать поле «Агрегат», но в своих поисках я обнаружил, что это невозможно выполнить с помощью настройки мастера/детали. Я также попытался просто перебирать детали ClientsDataSet следующим образом:

(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; 

Но это вызывает бесконечный цикл. Когда я отлаживаю эту часть кода, я обнаружил, что ... DataSet.First вызывает CalcFields (или что-то еще, что в свою очередь вызывает CalcFields).

Как я могу перебирать DataSet выбранных надстроек для динамического расчета общих затрат (при каждом изменении выбора или количества)?

--EDIT--

Я пытался настроить агрегатной на столе детали следующим образом:

  • Добавлена ​​TAggregate 'AggregatePrice'
  • Установите поля следующим образом: Активный - True Наименование - AggregatePrice ' Выражение - SUM (TotalPrice) GroupingLevel - 1 IndexName - ServiceId Visible - Правда

Когда я запускаю это я получаю сообщение об ошибке «„TotalPrice“поле не правильный тип calcualted поля для использования в качестве заполнителя, используйте internalcalc»

+0

> * «это не выполнимо с использованием настройки мастера/детали» * - Это неверно, вы еще читали о «TAggregateField» или «TAggregate» в документах? –

+0

Посмотрите мой EDIT в исходном вопросе. – BrianKE

+0

Я не вижу EDIT ... –

ответ

5

После вашего редактирования ответ кажется очевидным: используйте поле InternalCalc вместо простого CalcField!

Расчет по-прежнему выполняется внутри OnCalcField, но вы должны проверить TDataset.State для dsInternalCalc.

Это необходимо, потому что агрегаты вычисляются после dsInternalCalc, но до состояния dsCalcFields.

В качестве примечания стороны, поле InternalCalc может использоваться для индекса, но простой CalcField не может.

+0

Я не очень много использую поля InternalCalc, поэтому вы можете сказать мне, правильно ли я это сделал? Я изменил TotalPrice на InternalCalcField. Я удалил агрегат и на его месте создал AggregateField (AggregatePrice) с выражением «SUM (TotalPrice)» и установил IndexName во время выполнения для поля: TotalPrice и GroupingLevel: 1. Единственная проблема теперь в том, что когда CalcFields называется AggregatePrice, всегда Null. – BrianKE

+0

Предполагая, что TotalPrice совпадает с TotalCost в вашем вопросе, вы должны установить значение IndexName вместо TotalPrice. В противном случае агрегат строится над каждым значением TotalPrice, которое выглядит для меня совершенно бессмысленным. –

+0

Во всяком случае, я рекомендую прочитать отличную книгу Кэри Йенсена [Delphi in Depth: ClientDataSets] (http://jensendatasystems.com/cdsbook/) –

0

Один из способов использовать Клонированный Курсор для деталей - копию набора данных, который хранится в синхронизации с содержимым его источника, но который можно перемещать независимо.

например.

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; 

Имейте в виду, что клонированный курсор не будет иметь никаких вычисляемых полей или любое из событий, связанных с оригиналом, так что вам необходимо установить те снова, если это необходимо.