一个困扰我的RealThinClient调用服务端结果的问题,解决了这个,做三层数据库将会很轻松(100)

L

lssgj

Unregistered / Unconfirmed
GUEST, unregistred user!
我的思路:1客户端传送SQL语句到服务端,在服务端通过DBCLIENTDATASET取得数据,把DBCLIENTDATASET用SaveToStream使用RealThinClient的DelphiDataSetToRtc函数也可)后,作为参数传递给客户端;2.客户端再用LoadFromStream取得数据.具体过程是1.服务端使用TRtcFunction控件(名为Getdata)通过其OnExecute过程取得数据procedure TAppSrv_Module.GetdataFuncExecute(Sender: TRtcConnection; Param: TRtcFunctionInfo; Result: TRtcValue); procedure CanEditField(const readonly: Boolean;cs : TDataSet); var i : Integer; beginvar myStream:TMemoryStream;begin //CDS是一个DBCLIENTDATASET,通过DATASETPROVIDER和SQLQUERY,SQLCONNECTION取得数据 cds.CommandText:=Param.asWideString['QueryCmd']; //doshowsql('开始执行SQL'+chr(13)+chr(10)+cds.CommandText); cds.Close; cds.Open; myStream:=TMemoryStream.Create; CanEditField(false,cds); try cds.SaveToStream(myStream,dfbinary); myStream.Position:=0; Result.asByteStream:=myStream; finally myStream.Free; cds.Close; end;end;2.客户端数据模块中放上TRtcResult控件(名为RtcResultForGetData),这个控件有个过程是onReturn,按RealThinClient的原理,就是从这个过程取得服务端返回的结果.procedure TEM.RtcResultForSaveDataReturn(Sender: TRtcConnection; Data, Result: TRtcValue);begin Result.asByteStream.Position:=0; ClientGetdata.LoadFromStream(Result.asByteStream);end;我原以为以下函数中的Call(RtcResultForGetData或POST后就会马上角发上面这个过程,所以试图通过以下函数,从ClientGetdata(是一个TClientDataSet)取得数据,结果根据跟踪情况看,他总是执行完下面这个过程后才调用procedure TEM.RtcResultForSaveDataReturn(Sender: TRtcConnection; Data, Result: TRtcValue);也就是执行这一句: result:=ClientGetdata.Data 前ClientGetdata.根本没有从服务器取得数据. 如果程序其他地方调用getdata()后还有代码,他仍然是执行完getdata()后再把其后的所有代码执行完才会调用RtcResultForSaveDataReturn过程.不知道 RtcResultForSaveDataReturn究竟是被什么事件触发的,如果能在result:=ClientGetdata.Data;之前触发问题就解决了. 这是什么原因,是不是因为RealThinClient使用了线程的原因?请高手指教,也欢迎有兴趣的朋友共同讨论,我的QQ是532597053,realthinclient的网址是http://www.realthinclient.com,如果需要的,我测试代码也可以发出来.function TEM.getdata(psql: WideString): OleVariant;begin if ConnRemoteServer then begin with RtcClientModule do begin StartCalls; try with Data.NewFunction('getdata') do begin asWideString['QueryCmd']:=psql; end; Call(RtcResultForGetData); finally Post; result:=ClientGetdata.Data; end; end; end;
 
我在网上有下载它的三层例子.RtcDataSetToDelphi(DBFunc.GetRemoteQuery(edtQuery.Text),CDS);function TRemoteDBFunc.GetRemoteQuery(Qry:String):TrtcDataSet; begin Result := NIL; FStatus:=0; with FCliModule do begin // Function name should equal class Method name - for simplicity with Data.newFunction('GetRemoteQuery') do begin // Set all remote function parameters here ... asString['Qry'] := Qry; end; Call(FEventResult); // Using WaitForCompletion to block execution until we get a response if not WaitForCompletion then RaiseError(0,'GetRemoteQuery'); end; if FStatus<=0 then RaiseError(2,'GetRemoteQuery') // Check if the result we have received is an exception and raise it else if FLastResult.isType=rtc_Exception then raise Exception.Create(FLastResult.asException) else if FLastResult.isType=rtc_NULL then RaiseError(3,'GetRemoteQuery') // Check if the result is of our expected type and return the data else if FLastResult.isType=rtc_Dataset then With FLastResult do begin Result:=asDataset; // NOTE: Returned object will be destroyed on the next call to any function end else RaiseError(1,'GetRemoteQuery'); end;
 
1客户端传送SQL语句到服务端,在服务端通过DBCLIENTDATASET取得数据,把DBCLIENTDATASET用SaveToStream使用RealThinClient的DelphiDataSetToRtc函数也可)后,作为参数传递给客户端;2.客户端再用LoadFromStream取得数据.具体过程是1.服务端使用TRtcFunction控件(名为Getdata)通过其OnExecute过程取得数据===> Borland sorket/ RemObject都是这个原理呀.所有三层都是这个原理的.
 
个人感觉: RemObject和Borland sorket各有优缺点,以至于我还是认为Borland sorket会更稳定点.
 
根据freeman_m530的提示,问题已解决,用函数向导生成代码按自己的需要改一下,然后就可以了,对这个感兴趣的不多,有兴趣的可以跟我联系相互探讨.下面是我生成的代码:unit test; // RTC Remote Functions Wizard output file;(*Copyright ( c ) 2007 Glynn Owen,RealThinClient components,All Rights reserved.*)interfaceuses SysUtils, Classes, rtcInfo, rtcConn, rtcFunction, rtcCliModule;type Ttest = class private // Local objects FEventResult: TRtcResult; FLastResult: TRtcValue; // Pointer to external object FCliModule: TRtcClientModule; FStatus: shortint; protected { General-purpose Result Event handler } procedure ResultReturn(Sender: TRtcConnection; Data, Result: TRtcValue); { General-purpose Result Aborted handler } procedure ResultAborted(Sender: TRtcConnection; Data, Result: TRtcValue); public { Constructor and destructor } constructor Create(const ClientModule:TRtcClientModule); destructor Destroy; override;// BEGIN User-defined remote functions function getdata(QurySQL:string):TStream;// END User-defined remote functions end;implementationuses rtcDataCli;Var ErrorList:array[0..3] of string = ( ': Error waiting for a response.', ': Server response had incorrect data type.', ': Server not listening.', ': Function returned NULL.');procedure RaiseError(ErrNo:integer; Src:string);Begin Raise Exception.Create(Src+ErrorList[ErrNo]);End;procedure Ttest.ResultReturn(Sender: TRtcConnection; Data, Result: TRtcValue); begin // Extract the Result to our private variable FLastResult.Clear; FLastResult.asObject:=Result.asObject; Result.asObject:=nil; FStatus:=1; end;procedure Ttest.ResultAborted(Sender: TRtcConnection; Data, Result: TRtcValue); begin // Set OK to False (no valid response from server) FStatus:=-1; FLastResult.Clear; end;constructor Ttest.Create(const ClientModule:TRtcClientModule); begin inherited Create; FCliModule := ClientModule; // Create the "RtcResult" object and assign the event handler FEventResult:=TRtcResult.Create(nil); FEventResult.OnReturn:=ResultReturn; FEventResult.RequestAborted:=ResultAborted; // Create the ResultData object, where all results will be moved to FLastResult:=TRtcValue.Create; end;destructor Ttest.Destroy; begin FEventResult.Free; FLastResult.Free; inherited; end;function Ttest.getdata(QurySQL:string):TStream; begin Result := NIL; FStatus:=0; with FCliModule do begin // Function name should equal class Method name - for simplicity with Data.newFunction('getdata') do begin // Set all remote function parameters here ... asString['QurySQL'] := QurySQL; end; Call(FEventResult); // Using WaitForCompletion to block execution until we get a response if not WaitForCompletion then RaiseError(0,'getdata'); end; if FStatus<=0 then RaiseError(2,'getdata') // Check if the result we have received is an exception and raise it else if FLastResult.isType=rtc_Exception then raise Exception.Create(FLastResult.asException) else if FLastResult.isType=rtc_NULL then RaiseError(3,'getdata') // Check if the result is of our expected type and return the data else if FLastResult.isType=rtc_Bytestream then With FLastResult do begin Result:=asBytestream; Extract; // Returned object is not destroyed on next call end else RaiseError(1,'getdata'); end;end.在其他地方引用这个单元,象如下调用即可:procedure TForm1.Button1Click(Sender: TObject);var a:TStream;begin a:=mytest.getdata(Memo1.Text); a.Position:=0; test1.LoadFromStream(a);end;
 
散分....
 
多人接受答案了。
 
顶部