2017-10-09 74 views
6

使用Delphi西雅图。我有一个应用程序,它可以进行各种REST调用。其中一些调用可能会通过JSON返回10-20行,而其他调用可能会返回30-40行。我已将REST服务器设置为以1,000个批次返回行。当数据返回到我的客户端时,我使用RestDataAdapater,DataSource和客户端数据集来公开数据,就好像它是本地表一样。这部分似乎工作正常。如果我们在1000行的末尾,则更改URL并请求下一批1,000行。德尔福 - 如何创建一个通用的REST呼叫

我的挑战:我想抽象这样一个例程可以处理所有场景(至少对于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例程)中。我不希望每个调用例程都必须处理这个问题。

假设所有的例程只会向前移动,而不会向后移动。

回答

2

这里有几个选项供您考虑:

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

其他选项:
一)继承的TClientdataSet 您还可以通过获得来自的TClientdataSet和压倒一切的MoveBy一个新的类实现这一点:

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

如果继承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根据需要请求更多的记录。