kbmMW提供了QueryService,供我們在用戶端象傳統資料庫應用一樣,直接利用ClientQuery做SQL查詢,以及送出,并且能夠在客 戶端以事務的方式送出多個資料集,應該說,QueryService為我們提供了非常好的便利,快速将兩層應用轉為多層應用,如果用過ASTA,就會發 現,QueryService在對兩層應用的轉化上,要比其實作的更完美,層次更清晰。但在實際項目中,如果考慮應用伺服器對多平台的支援以及業務邏輯的 集中實作,那麼僅僅使用QueryService是不夠的,我們可能還要使用WebService等kbmMW提供的其他服務,這時候涉及到一個問題,如 何自己控制資料集的流化,就象QueryService一樣,通過在服務端将一個Query流化,在用戶端将收到的流再調入一個ClientQuery, 反之亦然。
對此,kbmMW為我們同樣提供了完美的機制,以實作用不同的格式的流在伺服器及用戶端間傳遞資料集。來看看伺服器端的實作:
在一個Service中放置一個TkbmMWUNIDACQuery,命名為q,設定好ConnectionPool及SessionName屬性;
再放置需要的kbmMWXXXStreamFormat,然後為Service增加一個方法SUM1,方法的第一個參數,定為用戶端要求傳遞的流格式,至此,可以看下面的實作代碼了。
// Functions published by the service.
//------------------------------------
function TwsYH.PerformSUM1(ClientIdent:TkbmMWClientIdentity; const
Args:array of Variant):Variant;
var
st:TkbmMWMemoryStream;
begin
// Enter code here to perform function SUM1
q.Close;
q.SQL.Add('Select * from T1');
q.Open;
st:=TkbmMWMemoryStream.Create;
case Args[0] of
0:q.SaveToStreamViaFormat(st,kbmMWBinaryStreamFormat1);
1:q.SaveToStreamViaFormat(st,kbmMWJSONStreamFormat1);
2:q.SaveToStreamViaFormat(st,kbmMWXMLStreamFormat1);
end;
resultStream.LoadFromStream(st);
st.Free;
實作很簡單,設定SQL,執行查詢,按用戶端要求的格式生成Stream,然後寫到ResultStream中。對于用戶端的實作,則正好相反:
procedure TForm6.Button5Click(Sender: TObject);
sfBin:TkbmMWBinaryStreamFormat;
sfJSON:TKbmMWJSONStreamFormat;
sfXML:TkbmMWXMLStreamFormat;
sfBin:=TkbmMWBinaryStreamFormat.Create(Self);
sfJSON:=TKbmMWJSONStreamFormat.Create(Self);
sfXML:=TkbmMWXMLStreamFormat.Create(Self);
try
label1.caption:=kbmMWSimpleClient1.Request('HTTPSERVICE','kbmMW_1.0','sum1',[rgSelectStreamFormat.ItemIndex]);
//
label1.caption:=kbmMWSimpleClient1.Request('QUERYSERVICES','1.0','sum1',[rgSelectStreamFormat.ItemIndex]);
kbmMWClientQuery2.Close;
case rgSelectStreamFormat.ItemIndex of
0:kbmMWClientQuery2.LoadFromStreamViaFormat(kbmMWSimpleClient1.ResultStream,sfBin);
1:kbmMWClientQuery2.LoadFromStreamViaFormat(kbmMWSimpleClient1.ResultStream,sfJSON);
2:kbmMWClientQuery2.LoadFromStreamViaFormat(kbmMWSimpleClient1.ResultStream,sfXML);
finally
sfBin.Free;
sfJSON.Free;
sfXML.Free;
end;
在用戶端,我們用SimpleClient向指定的Service發送請求,并将請求傳回的的ResultStream按請求的格式,調入一個ClientQuery中。
在做上面測試代碼時,遇到一個很奇怪的問題,就是當選擇BinaryStreamFormat時,ClientQuery加載流時出錯,而另外兩種格式正
常。向xalion請教,他的第一判斷,這不是bug,因為kbmMW第一個使用的就是Bin流,為此,我們還特意把流寫成檔案,對比伺服器與用戶端生成
的檔案是否不同,xalion還做了測試,把這個檔案加載到一個ClientQuery中,測試無問題,而在我這裡就是出錯。足足浪費幾個小時的時間,最
終xalion發現在我的代碼裡加上這句,問題得以解決:
kbmMWBinaryStreamFormat1.sfDef:=[sfLoadDef]
找到病因,原因就好查了,原來,當我們自己用流來操作Query時,使用的StreamFormat控件,不能被ClientQuery.TransportStreamFormat屬性引用(還有ClientTransactionResolve),為什麼呢?
procedure
TkbmMWCustomClientCursor.SetTransportStreamFormat(AFormat:TkbmMWCustomStreamFormat);
if AFormat=FTransportStreamFormat then exit;
if AFormat<>nil then
with AFormat do
sfDef:=[];//這裡ClientQuery把使用的StreamFormat的sfDef清空了!
sfDeltas:=[sfSaveDeltas];
sfData:=[sfLoadData];
ClientTransactionResolve也有同樣的代碼,清空使用的StreamFormat的sfDef屬性值。
至此,得到一條經驗:
就是當我們自己流化Query時,不要使用其他Query的TransportStreamFormat屬性引用的StreamFormat!