多层,无状态,ClientDataSet 分段读取服务器端的记录 |
|
pcplayer99
尊榮會員 發表:146 回覆:790 積分:632 註冊:2003-01-21 發送簡訊給我 |
unit UDataModule3;
{------------------------------------------------------------------------------ ClientDataSet 分段获取数据。有状态模式下,服务器端 select 出来100条,如果设置 ClientDataSet.PacketRecords := 10, 则 ClientDataSet 一次获取10条,ClientDataSet.GetNextPacket 获取后继 10 条。服务器端缓存住 1000 条,并帮客户端维护游标。 在无状态模式下,服务器端不帮客户端维护游标。而且,如果记录太多,不应该让服务器端一次取出 1000 条并缓存在服务器内存里面。 所以,这种情况下,服务器端应该是 Select first 10 * from MyTable 然后,客户端每次需要读取后面的数据时,就执行 ClientDataSet.GetNextPacket; 方法来向服务器请求下一段数据。 但是,这里的问题是:第一次读取数据,服务器里面只有10条,所有10条都已经读回客户端, 则 ClientDataSet.GetNextPacket 时不会有向服务器读取数据的动作。查其代码,里面会判断一下 ProviderEOF 属性。 所以,这里如果服务器端没有缓冲比10条更多的数据,则必须要重新设置 ProviderEOF 属性为 False 才能让它执行 GetNextPacket。 但是,ProviderEOF 属性是 Protected 的,在程序里无法访问。 So, 这里必须 Hack 一下 TClientDataSet。做法是这样的: Type TMyClientDataSet = class(TClientDataSet) public property ProviderEOF; end; 通过继承,把 ProviderEOF 属性公开。 然后,在 ClientDataSet2 需要设置 ProviderEOF 属性的地方,就可以这样: TMyClientDataSet(ClientDataSet2).ProviderEOF := False; 然后,再执行 ClientDataSet2.GetNextPacket; 它就会去向服务器请求下一段数据了。 然后,服务器怎么知道从哪里开始读取下一段数据? 在 ClientDataSet2.BeforeGetRecords 事件里面,将 OwnerData 设置为当前记录排序字段的最大值; 在服务器端的 DataSetProvider2.BeforeGetRecords 里面,为服务器端的 TQuery 的 select 参数赋值为 OwnerData。 这个程序的例子,排序字段就是主键字段,是一个整数编号字段。 很多时候,排序字段可以是时间字段。 以下代码测试通过。 pcplayer 2016-6-23 ------------------------------------------------------------------------------} interface uses System.SysUtils, System.Classes, FireDAC.UI.Intf, FireDAC.VCLUI.Wait, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.FB, FireDAC.Phys.FBDef, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, FireDAC.Comp.Client, FireDAC.Comp.DataSet, Data.DB, Datasnap.DBClient, Datasnap.Provider, FireDAC.Comp.UI; type TDataModule3 = class(TDataModule) FDGUIxWaitCursor1: TFDGUIxWaitCursor; FDConnection1: TFDConnection; FDManager1: TFDManager; FDTransaction1: TFDTransaction; DataSetProvider1: TDataSetProvider; ClientDataSet1: TClientDataSet; ClientDataSet1XUHAO: TIntegerField; ClientDataSet1ID: TWideStringField; ClientDataSet1FULLNAME: TWideStringField; ClientDataSet1EMAIL: TWideStringField; DataSource1: TDataSource; FDQuery1: TFDQuery; FDStoredProc1: TFDStoredProc; FDQuery2: TFDQuery; DataSetProvider2: TDataSetProvider; ClientDataSet2: TClientDataSet; DataSource2: TDataSource; CldTemp: TClientDataSet; procedure DataSetProvider2BeforeGetRecords(Sender: TObject; var OwnerData: OleVariant); procedure ClientDataSet2BeforeGetRecords(Sender: TObject; var OwnerData: OleVariant); private { Private declarations } public { Public declarations } procedure OpenClientDataSet2; end; //Hack 一下 TClientDataSet 以便这里能访问到其 ProviderEOF 属性。 TMyClientDataSet = class(TClientDataSet) public property ProviderEOF; end; var DataModule3: TDataModule3; implementation {%CLASSGROUP 'Vcl.Controls.TControl'} {$R *.dfm} { TDataModule3 } {------------------------------------------------------------------------------- 这里的 FDQuery2 的 SQL 是:select first 10 * from MyTable 这个 MyTable 里面的第一个主键字段是一个整数字段,叫做 XuHao 这里的 ClientDataSet2.PacketRecords 是默认的 -1。因为这是无状态模式。 -------------------------------------------------------------------------------} procedure TDataModule3.ClientDataSet2BeforeGetRecords(Sender: TObject; var OwnerData: OleVariant); begin OwnerData := ClientDataSet2.Params[0].Value; //将当前排序最大字段值传递给服务器。在本例子中不需要。 end; procedure TDataModule3.DataSetProvider2BeforeGetRecords(Sender: TObject; var OwnerData: OleVariant); begin FDQuery2.Params[0].Value := OwnerData; //给 服务器端的 select 参数赋值。在本例子中不需要。 end; procedure TDataModule3.OpenClientDataSet2; begin with ClientDataSet2 do begin if not Active then begin Params[0].Value := 0; Open; Exit; end; CldTemp.CloneCursor(ClientDataSet2, True); CldTemp.Last; Params[0].Value := CldTemp.FieldByName('XuHao').AsInteger; TMyClientDataSet(ClientDataSet2).ProviderEOF := False; //设置 ProviderEOF 为 False,后面的 GetNexPacket 才会被执行。 ClientDataSet2.GetNextPacket; end; end; end. 編輯記錄
pcplayer99 重新編輯於 2016-06-24 12:00:24, 註解 無‧
|
GrandRURU
站務副站長 發表:240 回覆:1680 積分:1874 註冊:2005-06-21 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |