我的挑战:我想抽象这个,以便一个例程可以处理所有场景(至少对于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根据需要请求更多的记录.