Я думаю, что вы имеете в виду OnCalcFields
, а не OnCreateFields
.
То, что вам нужно, безусловно, возможно, либо на стороне сервера, путем получения необходимых значений из предыдущей строки с использованием, например, подзапроса SQL, либо на стороне клиента с использованием вычисляемых полей. Этот ответ о выполнении на стороне клиента.
Проблема с выполнением расчетов на стороне клиента с использованием другой строки набора данных заключается в том, что для этого необходимо иметь возможность перемещать курсор набора данных во время события OnCalcFields. Однако в то время DataSet будет находиться либо в состоянии dsCalcFields, либо в dsInternalCal c, и, хотя это так, вы не можете легко перейти к другой строке в наборе данных. возможно сделать это, но требует объявления класса набора данных-потомков (TMyFDQuery), чтобы вы могли получить доступ к SetTempState
, необходимому для возврата в предыдущее состояние после того, как вы собрали необходимую информацию из «другая» строка и, если вам нужно больше одного поля, вам нужно где-то временно хранить значения. Таким образом, все становится беспорядочно.
Гораздо более чистый подход предполагает использование функционального сходства между наборами данных FireDA C и TClientDataSets. Одной из приятных особенностей TClientDatasSets является легкость, с которой вы можете перемещать содержимое набора данных между двумя CDS, просто выполняя
CDS2.Data := CDS1.Data;
FireDA C наборов данных, которые могут выполнять те же приемы, но между любыми типами наборов данных FD. , Вот что я бы сделал в вашей ситуации:
- Добавьте FDMemTable в вашу форму / модуль данных и скопируйте в него данные запроса в событии AfterOpen FDQuery, например:
procedure TForm2.FDQuery1AfterOpen(DataSet: TDataSet);
begin
FDQuery1.DisableControls;
try
FDMemTable1.Data := FDQuery1.Data;
FDMemTable1.Open;
finally
FDQuery1.First;
FDQuery1.EnableControls;
end;
end;
FDQuery1.First должен заставить его пересмотреть вычисленные поля после того, как станут доступны данные FDMemTable (во время начального FDQuery1.Open, конечно, это не может быть).
В событии FDQuery OnCalcFields используйте подобный код, чтобы основывать значения вычисляемых полей на значениях, взятых из предыдущей строки (если, конечно, есть одна, первая строка не может иметь "предыдущую" строку):
procedure TForm2.FDQuery1CalcFields(DataSet: TDataSet);
begin
if FDMemTable1.Active then begin
if FDMemTable1.Locate('ContactID', FDQuery1.FieldByName('ContactID').AsInteger, []) then begin
FDMemTable1.Prior;
if not FDMemTable1.Bof then begin
// Set FDQuery1's calculated fields that depend on prior row
FDQuery1.FieldByName('PriorRowID').AsInteger := FDMemTable1.FieldByName('ContactID').AsInteger;
end;
end;
end;
end;
В этом примере мой запрашиваемый набор данных имеет первичный ключ ContactID
, а вычисленное значение - это просто значение ContactID из предыдущей строки. Конечно, в реальной жизни было бы более эффективно использовать постоянные переменные поля, а не продолжать вызывать FieldByName
.
Я полагаю, что другой возможностью может быть использование метода CloneCursor для получения курсора поиска для доступа к «предыдущая» строка, но я сам не пробовал, и это все равно может оказаться невозможным (что происходит с вычисляемыми полями в копии CloneCuror?).