使用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例程)。我不希望每个调用例程都必须处理它。
假设所有例程只会向前移动,而不是向后移动。
答案 0 :(得分:2)
以下是您可以考虑的几个选项:
1)获取所有数据
对于大多数应用程序来说,内存中没有30-40,000行。即使你需要进行多次休息调用来获取数据,你也可以预先做到。如果您总是要遍历所有数据,那么如果您在循环中或在循环内部获取它,时间将是相同的:
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”命中时,那么你试着获得更多数据。这里的示例是一个独立的类,但您也可以在DataModule上创建这些公共方法。然后你不要像dm1.ds_Generic.DataSet.Next那样调用dm1.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, 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;
如果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根据需要请求更多的记录。