[转载红鱼儿]kbmmw 开发点滴:kbmMW数据集流化

简介: kbmMW提供了QueryService,供我们在客户端象传统数据库应用一样,直接利用ClientQuery做SQL查询,以及提交,并且能够在客 户端以事务的方式提交多个数据集,应该说,QueryService为我们提供了非常好的便利,快速将两层应用转为多层应用,如果用过ASTA,就会发 现,QueryService在对两层应用的转化上,要比其实现的更完美,层次更清晰。

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;
end;
实现很简单,设置SQL,执行查询,按客户端要求的格式生成Stream,然后写到ResultStream中。对于客户端的实现,则正好相反:

procedure TForm6.Button5Click(Sender: TObject);
var
  sfBin:TkbmMWBinaryStreamFormat;
  sfJSON:TKbmMWJSONStreamFormat;
  sfXML:TkbmMWXMLStreamFormat;
begin
  sfBin:=TkbmMWBinaryStreamFormat.Create(Self);
  sfJSON:=TKbmMWJSONStreamFormat.Create(Self);
  sfXML:=TkbmMWXMLStreamFormat.Create(Self);
  try
      label1.caption:=kbmMW SimpleClient1.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);
      end;
  finally
      sfBin.Free;
      sfJSON.Free;
      sfXML.Free;
  end;
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);
begin
     if AFormat=FTransportStreamFormat then exit;
     if AFormat<>nil then
        with AFormat do
        begin
             sfDef:=[]; //这里ClientQuery把使用的StreamFormat的sfDef清空了!
             sfDeltas:=[sfSaveDeltas];
             sfData:=[sfLoadData];
        end;
ClientTransactionResolve也有同样的代码,清空使用的StreamFormat的sfDef属性值。
至此,得到一条经验:

就是当我们自己流化Query时,不要使用其他Query的TransportStreamFormat属引用的StreamFormat!
目录
相关文章
零元学Expression Design 4 - Chapter 7 使用内建功能「Clone」来达成Path的影分身之术
原文:零元学Expression Design 4 - Chapter 7 使用内建功能「Clone」来达成Path的影分身之术 本章所介绍的是便利且快速的内建工具Clone ? 本章所介绍的是便利且快速的内建工具Clone ? ? 为什麽会说像是影分身之术呢? ? 请参照火影忍者(NARUTO): 《分身术》会分身术者,能以一身分出几身,几十身,乃至千百身。
1196 0
|
数据库 关系型数据库 MySQL
清幽傲竹实现的kbmMWServer数据库联接失败重联(转载红鱼儿)
1。修改kbmMWUnidac单元的TkbmMWUNIDACConnection.InternalOpenConnection方法,加上:            //支持unidac重联           FDatabase.
947 0
|
数据库
unidac 6.0.1 与kbmmw 的一点小摩擦
unidac 6.0.1  出来了,虽然支持sql server 直连等新特性,但是由于内部改动比较大, 导致与kmmmw 的集成起来存在有点小问题,就是如果数据库不是interbase 或者firebird 的话, 客户端访问kbmmw会出现"InterBase provider is not registered.
977 0
|
JSON 数据格式 数据库
[转载红鱼儿]kbmmw 开发点滴:kbmMW:Unknown property:indexes
利用kbmMW的QueryServices,对数据集进行提交,当改用JSON格式时,客户端提交时,会产生这个错误,明明已经更新数据库,也产生这个错误!如果换成Bin格式,则正常。 能过查看kbmMWJSONStreamFormat单元,问题产生在这行代码:nIndexDefs:=nDefs.AsArray['indexes']; 可以这样理解: 客户端提交数据后,服务器会返回一个错误结果数据集,不管有无错误,都要返回这个结果集。
900 0
|
SQL 数据库
[转载红鱼儿]kbmmw 开发点滴:kbmMWQuery插入记录
想利用TkbmMWUNIDACQuery插入一条记录,结果遇到问题,显示: 不允许从数据类型 sql_variant 到 varchar 的隐式转换。请使用 CONVERT 函数来运行此查询。这是什么问题啊?下面是出问题的代码,很常规的写法。
871 0
|
数据处理
[转载红鱼儿]kbmmw 开发点滴:kbmmW服务端事务控制
关于kbmMW的事务控制,前文已经在客户端实现,通过kbmMWClientTransaction来控制多个数据集的提交,在客户端提交多数据集,实际上,是在客户端实现业务逻辑,并通过一个事务来完成数据处理,这是违反多层架构的做法,实际项目中,需要在服务端,往往是利用多个数据集进行业务处理,并且用事务来控制,那我们该怎么办呢?换句话说,如何在服务实现事务的控制。
784 0
|
安全
[转载红鱼儿]kbmmw 开发点滴:TkbmMWLock用法
TStringList不是线程安全的,当我们在线程用到他是,要做保护。方法有两种,一种是用delphi自带的Critical,另外一种就是kbmMW为我们提供的TkbmMWLock类。 现在我们看看如何用TkbmMWLock为TStringList做线程安全: 1.
1074 0
[转载红鱼儿]kbmmw 开发点滴:kbmMWEventService的本质
在kbmMW创建服务向导中,有个“Eventoperated service”,其描述信息:同TkbmMWSimpleService一样,就是公布了一个附加的事件,来控制客户端请求,取代了ProcessRequest.
590 0
|
SQL 缓存
[转载红鱼儿]kbmmw 开发点滴:kbmMW缓存机制
kbmMW提供了稳顾机制,分为服务端的Cache及客户端的Cache。以客户端为例,当客户端发出相同的数据查询请求时,kbmMW会在客户端的Cache中查找,如果找到,则不再向服务器请求数据。 为了启用一个ClientQuery使用稳存,首先要设置其以下两个属性: kbmMWClientQuery.
841 0