Как заставить Client DataSet пересчитать рассчитанные и внутренние расчетные поля?

У меня есть ClientDatSet с несколькими полями fkInternalCalc. CDS не связан ни с одним провайдером; вместо этого он заполнялся на лету. Как я могу заставить CDS пересчитать все "исчисляемые" поля? Я не могу назвать Refresh(), потому что у провайдера нет необходимости обновлять данные. Единственный способ, с которым я пришел, заключался в том, чтобы перемещаться по всем записям, что не является лучшим способом.

PS: Я прочитал этот вопрос и этот пост, но я Мы надеемся на более элегантный способ.

Ответ 1

Я достигаю этого с помощью помощника (разделяется здесь на нужный), что позволяет вызывать защищенные методы без каких-либо взломов. Обязательно проверяйте DataSet.State = dsInternalCalc внутри полей OnCalcFields для полей fkInternalCalc.

type
  TClientDataSetHelper = class helper for TClientDataSet
  public
    function AssureEditing: Boolean;
    procedure InternalCalc;
  end;

function TClientDataSetHelper.AssureEditing: Boolean;
begin
  result := not (State in [dsEdit, dsInsert]);
  if result then
    Edit;
end;

procedure TClientDataSetHelper.InternalCalc;
var
  needsPost: Boolean;
  saveState: TDataSetState;
begin
  needsPost := AssureEditing;
  saveState := setTempState(dsInternalCalc);
  try
    RefreshInternalCalcFields(ActiveBuffer);
  finally
    RestoreState(saveState);
  end;
  if needsPost then
    Post;
end;

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

Ответ 2

Это немного взломанный, но он работает!

DBGrid.Height := 30; 
DBGrid.Height := 200; // Refresh all Rows after first
CalculatedProc(DataSet); // Refresh first calculated fields. (Write name of your calculate procedure)