Delphi - как создать общий вызов REST

Использование Delphi Seattle. У меня есть приложение, которое делает различные звонки REST. Некоторые из этих вызовов могут возвращать 10-20 строк через JSON, в то время как другие могут возвращать 30-40 тысяч строк. Я установил сервер REST для возврата строк партиями по 1000. Когда данные возвращаются моему клиенту, я использую RestDataAdapater, DataSource и Client Data Set для предоставления данных, как если бы это была локальная таблица. Эта часть, похоже, работает нормально. Если мы находимся в конце 1000 строк, то я изменяю URL-адрес и запросите следующую партию из 1000 строк.

моя задача: я хотел бы абстрагировать это, чтобы одна подпрограмма могла обрабатывать все сценарии (по крайней мере, для вызовов GET). Хитрые части - как я могу обрабатывать источник данных / клиентский набор данных 1,000 строк? Пример может помочь прояснить... Я хотел бы иметь возможность выполнить что-то подобное...

...
genericREST_Get(baseURL, resource, suffix);  // This would actually execute the REST call, where the components are in Datamodule DM1.
while not dm1.ds_Generic.DataSet.Eof do
        begin
       ... some kind of processing
       dm1.ds_Generic.DataSet.Next;
        end;

Как мне справиться с пересечением порога 1000 строк? Когда моя вызывающая программа (показанная выше) переходит из строки 1000 в 1001, REST API должен запросить следующий набор из 1000 строк с сервера. Хотя я знаю, как это сделать, я не знаю, где это сделать. Я хочу, чтобы "получить следующие 1000 строк" были в общей процедуре (она же процедура genericREST_Get). Я не хочу, чтобы каждый из процедур вызова имел дело с этим.

предположим, что все процедуры будут двигаться только вперед, а не назад.

1 ответов


вот несколько вариантов для вас, чтобы рассмотреть:

1) просто получить все данные
30-40 тысяч строк это не так много, чтобы держать в памяти для большинства приложений. Даже если вам нужно сделать несколько звонков, чтобы получить остальные данные, вы можете сделать это. Если вы всегда собираетесь перебирать все данные, время будет одинаковым, если вы получите его спереди или внутри цикла:

  repeat
    PartialData := genericREST_Get(baseURL, resource, suffix);
    // CopyDataSet is actually a FireDac method that I don't see on ClientDataSet
    // Basically just .Append and copy all fields with matching names.
    FullDataMemTable.CopyDataSet(PartialData);
  until PartialData.IsEmpty;

2) Если вы хотите иметь только одну группу данных в памяти, вы можете обернуть DataSet в другом объекте, который дублирует некоторые вызовы (Eof,FieldByName, Next и т. д.) Когда "Next" попадает в eof, вы пытаетесь получить больше данных. Пример здесь-автономный класс, но вы также можете сделать эти общедоступные методы на своем DataModule. Тогда вместо чего-то вроде dm1.ds_Generic.набор данных.Затем вы просто позвоните dm1.Следующий.

constructor TDataFetcher.Create(BaseUrl, Resource, Suffix: string);
begin
  FBaseUrl := BaseUrl;
  FResource := Resource;
  FSuffix := Suffix;
end;

procedure TDataFetcher.Open;
begin
  FData := genericREST_Get(FBaseURL, FResource, FSuffix);
end;

procedure TDataFetcher.GetNextData;
begin
  FData := genericREST_Get(FBaseURL, FResource, FSuffix);
end;

function TDataFetcher.Eof: boolean;
begin
  result := FData.Eof;
end;

function TDataFetcher.FieldByName(FieldName: string): TField;
begin
  result := FData.FieldByName(FieldName);
end;

procedure TDataFetcher.Next;
begin
  FData.Next;
  if FData.Eof then
  begin
    GetNextData;
  end;
end;

Другие Варианты:
a) наследовать от TClientDataSet Вы также можете выполнить это, получив новый класс из TClientDataSet и переопределение MoveBy:

function MoveBy(Distance: Integer): Integer; virtual;  

если унаследованный MoveBy устанавливает EOF, то вы можете загрузить следующий набор данных. Однако, если вы попробуете это, убедитесь, что вы рассматриваете все варианты использования. Например, что вы хотите сделать ,если вызывающий абонент использует.Последний? Это одно из преимуществ класса wrapper. Вызывающий не может делать ничего, кроме того, что вы выставляете напоказ.

function TMyDataSet.MoveBy(Distance: Integer): Integer; override;  
begin
  inherited MoveBy
  if self.Eof then
  begin
    FetchMoreData;
  end;
end;

b) FetchOnDemand
ClientDataSet имеет встроенную поддержку FetchOnDemand. Я не знаю, как это будет взаимодействовать с RestDataAdapter. Я уверен, что при достаточной работе вы можете получить поставщика, который вернет общее количество записей, а затем позволит ClientDataSet запросить больше записей по мере необходимости.