微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Delphi – 如何创建通用REST调用

使用Delphi Seattle.我有一个应用程序,可以进行各种REST调用.其中一些调用可能通过 JSON返回10-20行,而其他调用可能返回30-40,000行.我已将我的REST服务器设置为以1,000个批量返回行.当数据回到我的客户端时,我使用RestDataAdapater,DataSource和Client Data Set来公开数据,就像它是本地表一样.这部分似乎工作正常.如果我们在1000行的末尾,那么我更改URL,并请求下一批1,000行.

我的挑战:我想抽象这个,以便一个例程可以处理所有场景(至少对于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)获取所有数据
对于大多数应用程序来说,内存中没有30-40,000行.即使你需要进行多次休息调用获取数据,你也可以预先做到.如果您总是要遍历所有数据,那么如果您在循环中或在循环内部获取它,时间将是相同的:

repeat
    PartialData := genericREST_Get(baseURL,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”命中时,你会尝试获得更多数据.这里的示例是一个独立的类,但您也可以在DataModule上创建这些公共方法.然后你可以调用dm1.Next而不是像dm1.ds_Generic.DataSet.Next这样的东西.

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

如果Inherited MoveBy设置EOF,则可以加载下一组数据.但是,如果您尝试此操作,请确保考虑所有用例.例如,如果调用者使用.Last,您希望发生什么?这是包装类具有的一个优点.除了您公开的内容之外,调用者不能执行任何操作.

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

b)Fetchondemand
ClientDataSet内置了对FetchOnDemand支持.我不知道它将如何与RestDataAdapter交互.我敢肯定,如果有足够的工作,你可以获得一个返回总记录数的提供者,然后让ClientDataSet根据需要请求更多的记录.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐