本人一直使用DELPHL+SQL的两层设计程序,但是由于客户端出现问题后,程序改过后,必须从新将所有的客户机重装设计,现在想到了分布式多层数据
阅读了有关资料,在DELPHI分布式多层设计中,客户机常称为瘦客户机。本人理解也就是客户端只负责对数据的显示,对于数据的查询,更改,统计都通过应用服务器来实现,但事实似乎并非如此,对于数据的操作,都必须要在客户端中输入代码实现,也说是跟我原来两层设计的没有多大区别,这样何谓瘦,应用服务器只有连接数据库作用,那又如何能减负呢,大量的程序设计代码都集中在客户端上,这是我对分布式多层的理解。
请擅长DELPHI分布式多层设计的朋友,能对我以上的理解提出不同理解,高分送上。
大哥,瘦客户机指的是硬件结构好不好。
你说的这种叫做b/s结构的程序,也就是浏览器/服务器结构的程序,在简单一点就是网站。
你以前做的那种叫做c/s结构的程序,也就是客户端/服务器结构的程序。
delphi如果要作b/s结构的程序似乎很难。b/s结构一般都用jsp、asp、asp.net、php等来作。
欢迎访问我的论坛:)
http://www.chinesebloger.com
期待您的支持:)
你说的这种叫做b/s结构的程序,也就是浏览器/服务器结构的程序,在简单一点就是网站。
你以前做的那种叫做c/s结构的程序,也就是客户端/服务器结构的程序。
delphi如果要作b/s结构的程序似乎很难。b/s结构一般都用jsp、asp、asp.net、php等来作。
欢迎访问我的论坛:)
http://www.chinesebloger.com
期待您的支持:)
温馨提示:答案为网友推荐,仅供参考
第1个回答 2007-08-18
本人用delphi+Interbase做过一个商用软件《建筑工地材料管理系统》已经4年了。我使用的是 c/s结构。
以下是本人在网上收集的delphi编程技巧材料的第三章内容(共10章,原编写的章节就是第三章,她对我来说,起了很大作用,请参考指教。)
第三章 创建多层应用程序
一个多层的Client/Server应用程序在逻辑上划分为几个部分,分别在不同的机器上运行,这些机器既可以在一个局域网内,也可以在Internet上。多层体系结构最大的优势可以概括为两点,一是集中化的商业逻辑,另一个是客户程序可以做得很“瘦”。
目前较常见的是三层的体系结构,其中,最关键的是应用服务器,它在三层体系结构中起了承上启下的作用,所以,应用服务器又叫Data Broker。Delphi4可以创建应用服务器,也可以创建“瘦”客户。如果不怕麻烦的话,也可以创建数据库后端。
在更复杂的多层体系结构中,“瘦”客户与远程服务器之间可以加入更多的服务中间件,例如,可以加入一个安全服务中间件,或者加入一个转换中间件,专门用来处理不同平台共享数据的问题。一旦您真正理解了三层的体系结构,多层的体系结构就迎刃而解。
3.1 多层体系结构的概述
Delphi 4对多层体系结构的支持主要得益于它的MIDAS技术。MIDAS是Multi-tier Distributed Application Services Suite的简称。MIDAS技术与Delphi 4中的另一个关键技术DAX配合起来使用,可以使多层的体系结构分布在Intrenet/Intranet上。
3.1.1 多层体系结构的优势
在多层体系结构中,由于服务器集中实现了应用逻辑(又称商业规则),客户程序可以把重点放在显示数据和与用户交互上,客户程序甚至都不需要知道数据存储在哪儿。
具体来说,多层的体系结构具有如下优势:
在一个共享的中间层封装了商业规则。不同的客户程序可以共享同一个中间层,而不必由每个客户程序单独实现商业规则。
客户程序可以做得很“瘦”。因为很多复杂的工作由应用服务器代劳了,客户程序只需要关注用户界面本身。“瘦”客户程序更容易发布、安装、配置和维护。
实现了分布式数据处理。把一个应用程序分布在几个机器上运行,可以提高应用程序的性能,通过冗余配置还可以保证不会因为局部故障导致整个应用程序崩溃。
有利于安全。可以把一些敏感的功能放在有严密防护措施的层上,同时又不至于使用户界面变得复杂。Delphi 4中的CORBA或MTS支持较复杂的安全机制。
3.1.2 MIDAS技术
MIDAS技术是多层体系结构的关键。无论是应用服务器端还是客户端,MIDAS技术需要有DBCLIENT.DLL的支持,这个动态链接库用于管理数据包。发布MIDAS应用程序时需要购买服务器许可。
基于MIDAS的多层应用程序需要用到一些特殊的构件,这些构件分为四大种类:对象库中的远程数据模块。远程数据模块与普通的数据模块有些相似,不同的是,远程数据模块可以作为COM服务器或CORBA服务器让客户程序访问它的接口。
TDataSetProvider和TProvider构件。这两个构件用在应用服务器端,主要作用是提供IProvider接口,客户程序通过IProvider接口获得数据和更新数据集。
TClientDataSet构件。这是一个从TDataset继承下来的但不需要BDE的构件。MIDAS连接构件。包括TDCOMConnection、TSocketConnection、TCorbaConnection TOLEnterpriseConnection、TMIDASConnection和TRemoteServer。其中,TMIDASConnection和TRemoteServer是为了兼容Delphi3的代码而保留的。MIDAS连接构件的作用是为客户程序定位服务器和IProvider接口。每个MIDAS连接构件都以一种特定的通讯协议工作。
3.1.3 MIDAS应用程序是怎样工作的
用户首先要启动客户程序,客户程序将试图连接应用服务器,如果应用服务器还没有运行,客户程序将激活应用服务器,并从中获得IProvider接口。
客户程序向应用服务器请求数据。如果TClientDataSet的FetchOnDemand属性设为True,客户程序会根据需要自动检索附加的数据包如BLOB字段的值或嵌套表的内容。否则,客户程序需要显式地调用GetNextPacket才能获得这些附加的数据包。
应用服务器收到客户程序的请求后,就从远程数据库服务器那儿检索数据,并打包返回给客户程序
客户程序收到数据包后把包打开,然后显示或进行处理。
用户对数据进行编辑修改,然后向应用服务器申请更新数据,实际上也要打包。
应用服务器收到客户程序的申请后,就向远程数据库服务器申请更新数据。如果出错,应用服务器就把出错的记录返回给客户程序去核对。
客户程序核对并修改了数据后,既可以放弃此次更新,也可以继续此次更新。
3.1.4 客户程序的结构
对于最终用户来说,多层体系结构中的客户程序与两层体系结构中的应用程序没有什么区别,在结构上,客户程序就好像一个基于文件的单层应用程序一样,仍然通过标准的数据控件与用户交互。但与单层应用程序不同的是,多层体系结构中的客户程序是通过应用服务器提供的IProvider接口获得数据的,也通过IProvider接口申请更新数据。
注意:当使用MTS的时候,可以选择不使用IProvider接口。不使用IProvider接口的好处是,可以充分发挥MTS在处理事务方面的特长。
在客户程序中,MIDAS连接构件扮演着极其重要的角色。不同的MIDAS连接构件使用不同的通讯协议:
. TDCOMConnection DCOM
. TSocketConnection Windows Sockets (TCP/IP)l
. TOLEnterpriseConnection OLEnterprise (RPCs)
. TCorbaConnection CORBA (IIOP)
TRemoteServer和TMIDASConnection是为了兼容Delphi 3的代码而保留的。
3.1.5 应用服务器的结构
应用服务器的关键部件是远程数据模块,它提供了IDataBroker接口。当客户程序与应用服务器建立了连接,就通过IDataBroker接口来获得IProvider接口。
Delphi 4支持三种类型的远程数据模块:
TremoteDataModule。这是一个支持双重接口的自动化服务器,这种类型的远程数据模块适合于使用DCOM、TCP/IP或OLEnterprise方式。
TMTSDataModule。这也是一个支持双重接口的自动化服务器,用这种类型的远程数据模块创建的应用服务器是Active Library即动态链接库,适合于使用DCOM、TCP/IP或OLEnterprise方式。
TcorbaDataModule。这是CORBA服务器,适用于与CORBA客户通讯。
上述三种远程数据模块都可以作为容器,但只能放置非可视的构件。另外,远程数据模块上一般要放一个或几个TDataSetProvider或TProvider构件来提供IProvider接口 。
远程数据模块上也可以放TDatabase构件和TSession构件。
3.1.6 MTS
MTS是Microsoft Transaction Server的简称,是Microsoft为分布式环境下进行事务处理所设计的服务接口。使用TMTSDataModule类型的远程数据模块的优势是:
MTS为应用服务器提供了基于角色的安全机制。每个客户都扮演着一种角色,决定了他们能否访问远程数据模块的接口。TMTSDataModule有一个函数叫IsCallerInRole,可以用来检查客户的角色,然后有条件地开放该角色所允许的功能。
MTS提供了缓冲池的功能,它能把与数据库的连接放到池中,当一个客户不再需要连接时,另一个客户可以继续使用它,这样,应用服务器不必再次登录到远程数据库服务器。可能有的读者会想到,这个功能非常类似于TDatabase构件的KeepConnection属性。不过,要注意的是,如果用了TDatabase构件的话,KeepConnection属性最好设为False。
MTS提供了强大的事务处理能力,它的“两阶段提交”技术使得应用程序能够跨服务器处理事务。
可以用TMTSDataModule类型的远程数据模块实现一个MTS服务器,这个MTS服务器能够根据需要自动地激活或相反,换句话说,只有当远程数据模块接收到客户的连接请求时才创建模块的一个实例,这样能够最大程度地节省资源。
由此可见,MTS服务器可以有两种工作方式,一是单实例方式,一个实例能够处理多个客户的请求,不过,如果客户较多的话,远程数据模块就成了瓶颈,制约着应用服务器的性能。二是多实例方式,每个客户请求连接时都会创建远程数据模块的一个实例,这样,几个客户就可以同时访问数据库而不需要排队。
为了发挥MTS的上述优势,远程数据模块的实例必须做到与状态无关,而IProvider接口又依赖于状态信息,这就造成冲突。因此,TMTSDataModule类型的远程数据模块往往不用IProvider接口,而是自己创建一个接口来传递数据和申请更新。
注意:使用MTS的时候,在远程数据模块的实例激活之前不能连接数据库。
3.1.7 IDataBroker接口和IProvider接口
应用服务器上的远程数据模块支持IDataBroker接口,当客户程序与应用服务器连接以后,客户程序上的MIDAS连接构件就查找IDataBroker接口。
IDataBroker接口只实现了一个方法叫GetProviderNames,调用这个方法可以获得一个列表,这个列表列出了应用服务器上的TDataSetProvider和TProvider构件。
TClientDataSet的ProviderName属性可以指定其中一个TDataSetProvider或TProvider构件。当客户程序通过IDataBroker接口的GetProviderNames以及TClientDataSet的ProviderName属性指定了应用服务器上的一个TDataSetProvider或TProvider构件后,只要客户还在引用IProvider接口,远程数据模块的状态就应该保持,这与MTS的许多特点是有冲突的,也会与单实例的CORBA服务器发生冲突。
客户程序与应用服务器之间通过IProvider接口交换数据,不过,大部分客户程序并不直接使用IProvider接口,而是通过TClientDataSet的属性和方法间接地使用IProvider接口。 不过,也可以通过Provider属性获得IProvider接口,然后直接访问IProvider接口。
下面这个表列出了IProvider接口的属性和方法,同时列出了TProvider构件以及TClientDataSet构件中与之对应的属性和方法。
IProvider TProvider TClientDataset
ApplyUpdates ApplyUpdates ApplyUpdates
Constraints属性 Constraints 客户程序只能通过IProvider接口访问这个属性
Data Data Data
DataRequest DataRequest 客户程序只能通过IProvider接口访问这个方法
Get_Constraints Constraints 客户程序只能通过IProvider接口访问这个方法
Get_Data Get_Data 用于实现Data属性
GetMetaData GetRecords(Count = 0) 内部使用
GetRecords GetRecords 用于GetNextPacketResetReset内部使用
Set_Constraints Constraints 客户程序只能通过IProvider接口访问这个属性
SetParams SetParams 用于Params属性
注意:IProvider接口的许多属性和方法依赖于远程数据模块的状态信息,正因为如此,在使用CORBA或MTS的应用程序中一般不要用IProvider接口。
3.2 选择连接方式
在客户程序与应用服务器之间,Delphi 4提供了四种不同类型的连接方式或者说通讯协议,包括DCOM、TCP/IP、OLEnterprise和CORBA。这些不同的连接方式都各有利弊,到底选择哪种连接方式,取决于客户的数量、客户的分布情况以及怎样发布应用程序。
DCOM是一种最直接的连接方式,它不需要专门的运行期软件支持。不过,Windows 95 不支持DCOM,除非安装了DCOM95程序。
要使用MTS安全服务,最好使用DCOM连接方式。MTS的安全服务是基于角色的,当一个客户通过DCOM访问MTS时,DCOM会告诉MTS有关客户的信息,MTS据此来决定客户的角色。如果用其他连接方式,需要有专门的运行期软件支持,客户的调用首先被传递给这些运行期软件而不是MTS,MTS就不能尽快指派角色。
TCP/IP连接方式的适合范围非常广泛,例如,如果客户程序要以ActiveForm的形式分布在Web上,最好采用TCP/IP连接方式,因为您无法肯定下载ActiveForm的计算机是否支持DCOM,而支持TCP/IP的环境是很普遍的。
要使用TCP/IP连接方式,应用服务器端必须运行一个专门的运行期软件ScktSrver.exe或ScktSrvc.exe,其中,ScktSrvc.exe只适合于Windows NT,可以作为一个服务在后台运行。与DCOM连接方式不同的是,客户的请求首先传递给ScktSrver.exe或ScktSrvc.exe,然后再创建远程数据模块的实例,而不是由客户的调用直接创建远程数据模块的实例。客户程序上的MIDAS连接构件通过IProvider接口与ScktSrvr.exe or ScktSrvc.exe通讯。
不过,客户程序很有可能在没有正常释放对IProvider 接口的引用之前出现异常,而TCP/IP连接方式无法检测到这种情况,更无法通知应用服务器,因此,有可能造成应用服务器上的资源被占用后得不到释放的后果。
如果要在应用服务器端使用Business Object Broker,就要使用OLEnterprise连接方式。此时,应用服务器端和客户端都要安装OLEnterprise运行期软件。
Delphi 4是目前唯一支持CORBA的开发工具。基于CORBA的客户程序和应用服务器可以与其他基于CORBA的应用程序无缝对接。要使用CORBA连接方式,需要ORB的支持,它提供了类似于Business Object Broker的功能。
3.3 创建应用服务器的一般步骤
要创建一个多层Client/Server应用程序,首先要创建应用服务器,然后注册或安装应用服务器,只有应用服务器已注册并且正在运行的情况下,才能创建客户程序。对于客户程序来说,既可以在设计期连接应用服务器,也可以在运行期连接应用服务器。
注意:如果客户程序与应用服务器不在同一个系统中,必须在客户计算机上注册或安装应用服务器,这样,在设计期就可以连接应用服务器。
创建一个应用服务器与创建一个两层的数据库应用程序有些相似,主要的区别是,应用服务器需要提供IProvider接口,这一般是通过TDataSetProvider或TProvider构件提供的,也可以通过数据集构件如TTable的Provider属性提供。创建应用服务器的一般步骤是:
第一步是使用"File"菜单上的"New Application"命令开始一个新项目,然后使用File菜单上的New命令,选取Multi页,如图3.1所示。
选择一个远程数据模块。如果要创建一个COM自动化服务器,允许客户通过DCOM、TCP/IP、OLEnterprise等方式访问此服务器,选择RemoteMod。如果要创建一个允许客户通过MTS访问的Active Library,选择MTSData Module。如果要创建一个CORBA服务器,选择Corba Data。
第二步是把一个数据集构件如TTable、TQuery或TStoredProc放到远程数据模块上,并进行有关设置,使得它们能访问远程的SQL数据库。尽量不要把TDatabase构件放到远程数据模块上,因为这可能引起名称冲突。如果实在要用TDatabase构件来连接SQL数据库,建议把TDatabase构件放到另一个数据模块上,然后引用这个数据模块的单元文件。
第三步是把TDataSetProvider或TProvider构件放到远程数据模块上,有一个数据集构件,就要有一个TDataSetProvider或TProvider构件与之对应。然后,用鼠标右键单击TDataSetProvider或TProvider构件,在弹出的菜单中选择ExportFrom <Name> in Data Module命令,这是为了引出Provider接口,在类型库中注册。
第四步是设置TDataSetProvider或TProvider构件的DataSet属性指定要访问的数据库,实际上就是第二步所放的数据集构件。
第五步是编写代码,实现商业规则。当然,这一步远远不是几句话所能说清楚的。
第六步是保存、编译、注册或安装应用服务器。
如果使用DCOM、TCP/IP、OLEnterprise作为通讯协议,应用服务器就好像一个自动化服务器一样,必须像ActiveX或COM服务器那样注册。
如果使用MTS,应用服务器是DLL而不是EXE,这时候不需要注册应用服务器,而要把这个DLL作为MTS对象安装到MTS包中。
如果使用CORBA,可以不注册但最好注册。如果要使客户程序对服务器接口的调用在运行期是动态确定的,就要在接口库(Interface Repository)中安装服务器的接口。如果要使客户程序能自动激活应用服务器(如果还没有运行的话),应用服务器就必须用OAD(Object Activation Daemon)注册。
第七步是如果应用服务器没有使用DCOM,您必须安装有关的运行期软件,因为其他连接方式需要这些运行期软件的支持。例如,对于TCP/IP来说,需要安装ScktSrvr.exe或ScktSrvc.exe,后者只能运行在Windows NT环境下。对于OLEnterprise来说,需要安装OLEnterprise运行期版本。对于CORBA来说,需要安装VisiBroker ORB。
3.4 远程数据模块
应用服务器的关键部件是远程数据模块。Delphi 4支持三种类型的远程数据模块,分别是TRemoteDataModule、TMTSDataModule、TCorbaDataModule。
3.4.1 TRemoteDataModule
要加入一个TRemoteDataModule类型的远程数据模块,使用“File”菜单上的“New”命令,选取“Multitier”页,双击“Remote Data Module”图标,弹出“Remote Data Module Wizard”对话框,如图3.2所示。
在“Class Name”框内键入远程数据模块的类名,不必以T打头。Delphi 4将以此名生成一个TRemoteDataModule的派生类,并以此名生成有关接口。例如,假如在“Class Name”框内键入“MyDataServer”, 远程数据模块的类名就是TMyDataServer,它所实现的接口叫IMyDataServer,其祖先接口是IDataBroker。
在“Threading Model”框内选择一种线程模式。可以选“Single-threaded”、“Apartment-threaded”、“Free-threaded”或者“Both”。
在“Instancing”框内选择是否根据客户的请求生成远程数据模块的多个实例,可以选“Single instance”或“Multiple instance”。
3.4.2 TMTSDataModule
要加入一个TMTSDataModule类型的远程数据模块,使用“File”菜单上的“New”命令,选择“Multitier”页,双击“MTS Data Module”图标,弹出“MTSData Module Wizard”对话框,如图3.3所示。
图3.3 MTS Data Module对话框
在“Class Name”框内键入远程数据模块的类名,不必以T打头。Delphi 4将以此名生成一个TMTSDataModule的派生类,并以此名生成有关接口。例如, 假设在“Class Name”框内键入“MyDataServer”, 远程数据模块的类名就是TMyDataServer,它所实现的接口叫IMyDataServer,其祖先接口是IDataBroker。
对于TMTSDataModule类型的远程数据模块来说,必须在“ThreadingModel”框内选择一种线程模式。可以选“Single”、“Apartment”或者“Both”。在“Transaction Attributes”框内选择事务属性:
如选择“Requires a transaction”,每当客户访问远程数据模块的接口时,都与当前的事务是相关的。客户不可能在事务中再申请一个新的事务。
如选择“Requires a new transaction”,每当客户访问远程数据模块的接口时,都自动开始一个新的事务。如选择“Supports transactions”,远程数据模块可以用在事务的环境中,客户访问远程数据模块的接口时必须申请一个新的事务。
如选择“Does not support transactions”,远程数据模块不能用在事务的环境中。
注意:MTS对象只能加入到ActiveX项目中,如果试图在一个EXE项目中加入TMTSDataModule类型的远程数据模块,Delphi 4会显示一个提示框,如图3.4所示。
图3.4 一个提示框
3.4.3 TCORBADataModule
要加入一个TCorbaDataModule类型的远程数据模块,使用“File”菜单上的“New”命令,选取“Multitier”页,双击“CORBA Data Module”图标,弹出“CORBA Data Module Wizard”对话框,如图3.5所示。
图3.5 CORBA Data Module对话框
在“Class Name”框内键入远程数据模块的类名,不必以T打头。Delphi 4将以此名生成一个TCorbaDataModule的派生类,并以此名生成有关接口。例如,假设在“Class Name”框内键入“MyDataServer”, 远程数据模块的类名就是TMyDataServer,它所实现的接口叫IMyDataServer,其祖先接口是IDataBroker。
在“Instancing”框内指定应用服务器怎样创建远程数据模块的实例,可以选“Shared Instance”或者“Instance-Per-Client”。
如果选“Shared Instance”,应用服务器只创建远程数据模块的一个实例来处理所有客户的请求,因此,远程数据模块必须与状态无关,换句话说,就是不能使用IProvider接口。
如果选“Instance-Per-Client”,每当一个客户试图连接时,远程数据模块都会生成一个实例。只要客户与应用服务器的连接没有断开,远程数据模块的实例就一直存在。这种模式下,允许使用IProvider接口。唯一要考虑的问题是,客户程序有可能意外终止,导致没有正常地断开与应用服务器的连接。应用服务器为了避免不必要的资源浪费,可以定期地检查客户是否正在运行,如没有,就手工把远程数据模块的实例删掉。
在“Threading Model”框内选择一种线程模式。可以选“Single-threaded”、“Multi-threaded”。
3.5 Provider
远程数据模块上往往要放一个或几个TDataSetProvider或TProvider构件,用于提供IProvider接口。有时候,也可以不显式地使用TDataSetProvider或TProvider构件,而是由数据集构件如TTable、TQuery或TStoredProc的Provider属性间接地提供IProvider接口。
显式地使用TDataSetProvider或TProvider构件的好处是,可以直接控制数据包中包含哪些信息、应用服务器怎样响应客户的请求。如果显式地使用了TDataSetProvider或TProvider构件,必须设置他们的DataSet属性指定要访问的数据集。
3.5.1 控制数据包中的字段
要控制哪些字段包含到数据包中,首先要创建永久字段。以后,只有永久字段才加入到数据包中。如果不创建永久字段的话,数据集中的所有字段都将加入到数据包中。
如果创建的永久字段中包含计算字段,由于计算字段的值是在运行期计算出来的,这些字段虽然也能加入到数据包中,但这些字段传递到客户端后就变成只读的。
由于客户程序很有可能要编辑修改数据,并且要把编辑修改后的数据申请更新到应用服务器上,因此,您创建的永久字段的数量不能太少,否则,很有可能出现重复的记录。举例来说,假设有一个学生成绩表,由学号、姓名、语文成绩、数学成绩、历史成绩等字段组成,如果创建的永久字段中只包含语文成绩、数学成绩、历史成绩等字段,很有可能出现两名学生的上述成绩完全一样,也就是说有重复的记录,这是不允许的。
如果实在不想使客户程序看到某个字段,而如果没有这个字段的话很有可能出现上述错误,这时候您可以让这个字段(TField对象)的ProviderFlags属性包含pfHidden元素,表示这个字段虽然加入到数据包中,但却是隐含的,客户看不到它。
特别要注意的是,如果使用TQuery作为应用服务器上的数据集构件,SQL语句应当选择足够多的字段,即使客户程序并不需要这么多字段,否则,就有可能出现上述错误。
3.5.2 Options属性
这个属性是一个集合,用于设置有关打包和传递的选项。
如果包含poFetchBlobsOnDemand元素,表示BLOB字段一般不放到包中,除非客户端的TClientDataSet构件的FetchOnDemand属性设为True或者显式地调用FetchBlobs。
如果包含poFetchDetailsOnDemand元素,表示嵌套表中的字段不放到包中,除非客户端的TClientDataSet构件的FetchOnDemand属性设为True或者显式地调用FetchDetails。
如果包含poIncFieldProps元素,表示把字段的属性也放到包中,包括Alignment、MinValue、DisplayLabel、DisplayWidth、Visible、DisplayFormat、MaxValue、EditFormat、Currency、EditMask、DisplayValues等属性。
如果包含poCascadeDeletes元素,当父表中的某条记录被删除时就把子表中的相应记录也删除。
如果包含poCascadeUpdates元素,当父表的关键字段的值变化时自动更新子表的记录。
如果包含poReadOnly元素,表示不允许“瘦”客户向TDataSetProvider申请更新数据。
3.5.3 在数据包中加入自定义的信息
当客户端通过IProvider 接口调用DataRequest函数请求数据时将在应用服务器端触发OnGetDataSetPropertiesevent事件,这样,应用服务器就有机会在数据包中加入一些自定义的信息。客户端可以调用GetOptionalParam来检索这些信息。
OnGetDataSetPropertiesevent事件是这样声明的:
TGetDSProps = Procedure(Sender: TObject; DataSet: TDataSet; out Properties:OleVariant);
其中,Properties参数是一个可变类型的数组,用于指定要加入的信息。Properties参数的每个元素由三部分组成:名称、值和一个布尔数。Delphi 4定义了几个标准的信息名称,它们是UNIQUE_KEY、DEFAULT_ORDER、CHANGE_LOG、SERVER_COL、CONSTRAINTS、DATASET_CONTEXT、DATASET_DELTA、LCID、BDERECORD_X、TABLE_NAME、MD_FIELDLINKS、UPDATEMODE。程序示例如下:
Procedure TAppServer.Provider1GetDataSetProperties(Sender: TObject; DataSet: TDataSet; out Properties:OleVariant);
Begin
Properties := VarArrayCreate([0,1], varVariant);
Properties[0] := VarArrayOf(['TimeProvided', Now, True]);
Properties[1] := VarArrayOf(['TableSize', DataSet.RecordCount, False]);
End;
上面这个程序中,加入了两个自定义的信息,一个叫TimeProvided,它的值是当前的日期和时间,True表示这个信息可以由客户端返回给应用服务器。另一个信息叫TableSize,它的值是数据集的记录数,False表示这个信息不可以由客户端返回给应用服务器。
以后,当客户端申请更新数据时,TDataSetProvider的OnUpdateData事件可以读出数据包中的信息。程序示例如下:
Procedure TAppServer.Provider1Updat
以下是本人在网上收集的delphi编程技巧材料的第三章内容(共10章,原编写的章节就是第三章,她对我来说,起了很大作用,请参考指教。)
第三章 创建多层应用程序
一个多层的Client/Server应用程序在逻辑上划分为几个部分,分别在不同的机器上运行,这些机器既可以在一个局域网内,也可以在Internet上。多层体系结构最大的优势可以概括为两点,一是集中化的商业逻辑,另一个是客户程序可以做得很“瘦”。
目前较常见的是三层的体系结构,其中,最关键的是应用服务器,它在三层体系结构中起了承上启下的作用,所以,应用服务器又叫Data Broker。Delphi4可以创建应用服务器,也可以创建“瘦”客户。如果不怕麻烦的话,也可以创建数据库后端。
在更复杂的多层体系结构中,“瘦”客户与远程服务器之间可以加入更多的服务中间件,例如,可以加入一个安全服务中间件,或者加入一个转换中间件,专门用来处理不同平台共享数据的问题。一旦您真正理解了三层的体系结构,多层的体系结构就迎刃而解。
3.1 多层体系结构的概述
Delphi 4对多层体系结构的支持主要得益于它的MIDAS技术。MIDAS是Multi-tier Distributed Application Services Suite的简称。MIDAS技术与Delphi 4中的另一个关键技术DAX配合起来使用,可以使多层的体系结构分布在Intrenet/Intranet上。
3.1.1 多层体系结构的优势
在多层体系结构中,由于服务器集中实现了应用逻辑(又称商业规则),客户程序可以把重点放在显示数据和与用户交互上,客户程序甚至都不需要知道数据存储在哪儿。
具体来说,多层的体系结构具有如下优势:
在一个共享的中间层封装了商业规则。不同的客户程序可以共享同一个中间层,而不必由每个客户程序单独实现商业规则。
客户程序可以做得很“瘦”。因为很多复杂的工作由应用服务器代劳了,客户程序只需要关注用户界面本身。“瘦”客户程序更容易发布、安装、配置和维护。
实现了分布式数据处理。把一个应用程序分布在几个机器上运行,可以提高应用程序的性能,通过冗余配置还可以保证不会因为局部故障导致整个应用程序崩溃。
有利于安全。可以把一些敏感的功能放在有严密防护措施的层上,同时又不至于使用户界面变得复杂。Delphi 4中的CORBA或MTS支持较复杂的安全机制。
3.1.2 MIDAS技术
MIDAS技术是多层体系结构的关键。无论是应用服务器端还是客户端,MIDAS技术需要有DBCLIENT.DLL的支持,这个动态链接库用于管理数据包。发布MIDAS应用程序时需要购买服务器许可。
基于MIDAS的多层应用程序需要用到一些特殊的构件,这些构件分为四大种类:对象库中的远程数据模块。远程数据模块与普通的数据模块有些相似,不同的是,远程数据模块可以作为COM服务器或CORBA服务器让客户程序访问它的接口。
TDataSetProvider和TProvider构件。这两个构件用在应用服务器端,主要作用是提供IProvider接口,客户程序通过IProvider接口获得数据和更新数据集。
TClientDataSet构件。这是一个从TDataset继承下来的但不需要BDE的构件。MIDAS连接构件。包括TDCOMConnection、TSocketConnection、TCorbaConnection TOLEnterpriseConnection、TMIDASConnection和TRemoteServer。其中,TMIDASConnection和TRemoteServer是为了兼容Delphi3的代码而保留的。MIDAS连接构件的作用是为客户程序定位服务器和IProvider接口。每个MIDAS连接构件都以一种特定的通讯协议工作。
3.1.3 MIDAS应用程序是怎样工作的
用户首先要启动客户程序,客户程序将试图连接应用服务器,如果应用服务器还没有运行,客户程序将激活应用服务器,并从中获得IProvider接口。
客户程序向应用服务器请求数据。如果TClientDataSet的FetchOnDemand属性设为True,客户程序会根据需要自动检索附加的数据包如BLOB字段的值或嵌套表的内容。否则,客户程序需要显式地调用GetNextPacket才能获得这些附加的数据包。
应用服务器收到客户程序的请求后,就从远程数据库服务器那儿检索数据,并打包返回给客户程序
客户程序收到数据包后把包打开,然后显示或进行处理。
用户对数据进行编辑修改,然后向应用服务器申请更新数据,实际上也要打包。
应用服务器收到客户程序的申请后,就向远程数据库服务器申请更新数据。如果出错,应用服务器就把出错的记录返回给客户程序去核对。
客户程序核对并修改了数据后,既可以放弃此次更新,也可以继续此次更新。
3.1.4 客户程序的结构
对于最终用户来说,多层体系结构中的客户程序与两层体系结构中的应用程序没有什么区别,在结构上,客户程序就好像一个基于文件的单层应用程序一样,仍然通过标准的数据控件与用户交互。但与单层应用程序不同的是,多层体系结构中的客户程序是通过应用服务器提供的IProvider接口获得数据的,也通过IProvider接口申请更新数据。
注意:当使用MTS的时候,可以选择不使用IProvider接口。不使用IProvider接口的好处是,可以充分发挥MTS在处理事务方面的特长。
在客户程序中,MIDAS连接构件扮演着极其重要的角色。不同的MIDAS连接构件使用不同的通讯协议:
. TDCOMConnection DCOM
. TSocketConnection Windows Sockets (TCP/IP)l
. TOLEnterpriseConnection OLEnterprise (RPCs)
. TCorbaConnection CORBA (IIOP)
TRemoteServer和TMIDASConnection是为了兼容Delphi 3的代码而保留的。
3.1.5 应用服务器的结构
应用服务器的关键部件是远程数据模块,它提供了IDataBroker接口。当客户程序与应用服务器建立了连接,就通过IDataBroker接口来获得IProvider接口。
Delphi 4支持三种类型的远程数据模块:
TremoteDataModule。这是一个支持双重接口的自动化服务器,这种类型的远程数据模块适合于使用DCOM、TCP/IP或OLEnterprise方式。
TMTSDataModule。这也是一个支持双重接口的自动化服务器,用这种类型的远程数据模块创建的应用服务器是Active Library即动态链接库,适合于使用DCOM、TCP/IP或OLEnterprise方式。
TcorbaDataModule。这是CORBA服务器,适用于与CORBA客户通讯。
上述三种远程数据模块都可以作为容器,但只能放置非可视的构件。另外,远程数据模块上一般要放一个或几个TDataSetProvider或TProvider构件来提供IProvider接口 。
远程数据模块上也可以放TDatabase构件和TSession构件。
3.1.6 MTS
MTS是Microsoft Transaction Server的简称,是Microsoft为分布式环境下进行事务处理所设计的服务接口。使用TMTSDataModule类型的远程数据模块的优势是:
MTS为应用服务器提供了基于角色的安全机制。每个客户都扮演着一种角色,决定了他们能否访问远程数据模块的接口。TMTSDataModule有一个函数叫IsCallerInRole,可以用来检查客户的角色,然后有条件地开放该角色所允许的功能。
MTS提供了缓冲池的功能,它能把与数据库的连接放到池中,当一个客户不再需要连接时,另一个客户可以继续使用它,这样,应用服务器不必再次登录到远程数据库服务器。可能有的读者会想到,这个功能非常类似于TDatabase构件的KeepConnection属性。不过,要注意的是,如果用了TDatabase构件的话,KeepConnection属性最好设为False。
MTS提供了强大的事务处理能力,它的“两阶段提交”技术使得应用程序能够跨服务器处理事务。
可以用TMTSDataModule类型的远程数据模块实现一个MTS服务器,这个MTS服务器能够根据需要自动地激活或相反,换句话说,只有当远程数据模块接收到客户的连接请求时才创建模块的一个实例,这样能够最大程度地节省资源。
由此可见,MTS服务器可以有两种工作方式,一是单实例方式,一个实例能够处理多个客户的请求,不过,如果客户较多的话,远程数据模块就成了瓶颈,制约着应用服务器的性能。二是多实例方式,每个客户请求连接时都会创建远程数据模块的一个实例,这样,几个客户就可以同时访问数据库而不需要排队。
为了发挥MTS的上述优势,远程数据模块的实例必须做到与状态无关,而IProvider接口又依赖于状态信息,这就造成冲突。因此,TMTSDataModule类型的远程数据模块往往不用IProvider接口,而是自己创建一个接口来传递数据和申请更新。
注意:使用MTS的时候,在远程数据模块的实例激活之前不能连接数据库。
3.1.7 IDataBroker接口和IProvider接口
应用服务器上的远程数据模块支持IDataBroker接口,当客户程序与应用服务器连接以后,客户程序上的MIDAS连接构件就查找IDataBroker接口。
IDataBroker接口只实现了一个方法叫GetProviderNames,调用这个方法可以获得一个列表,这个列表列出了应用服务器上的TDataSetProvider和TProvider构件。
TClientDataSet的ProviderName属性可以指定其中一个TDataSetProvider或TProvider构件。当客户程序通过IDataBroker接口的GetProviderNames以及TClientDataSet的ProviderName属性指定了应用服务器上的一个TDataSetProvider或TProvider构件后,只要客户还在引用IProvider接口,远程数据模块的状态就应该保持,这与MTS的许多特点是有冲突的,也会与单实例的CORBA服务器发生冲突。
客户程序与应用服务器之间通过IProvider接口交换数据,不过,大部分客户程序并不直接使用IProvider接口,而是通过TClientDataSet的属性和方法间接地使用IProvider接口。 不过,也可以通过Provider属性获得IProvider接口,然后直接访问IProvider接口。
下面这个表列出了IProvider接口的属性和方法,同时列出了TProvider构件以及TClientDataSet构件中与之对应的属性和方法。
IProvider TProvider TClientDataset
ApplyUpdates ApplyUpdates ApplyUpdates
Constraints属性 Constraints 客户程序只能通过IProvider接口访问这个属性
Data Data Data
DataRequest DataRequest 客户程序只能通过IProvider接口访问这个方法
Get_Constraints Constraints 客户程序只能通过IProvider接口访问这个方法
Get_Data Get_Data 用于实现Data属性
GetMetaData GetRecords(Count = 0) 内部使用
GetRecords GetRecords 用于GetNextPacketResetReset内部使用
Set_Constraints Constraints 客户程序只能通过IProvider接口访问这个属性
SetParams SetParams 用于Params属性
注意:IProvider接口的许多属性和方法依赖于远程数据模块的状态信息,正因为如此,在使用CORBA或MTS的应用程序中一般不要用IProvider接口。
3.2 选择连接方式
在客户程序与应用服务器之间,Delphi 4提供了四种不同类型的连接方式或者说通讯协议,包括DCOM、TCP/IP、OLEnterprise和CORBA。这些不同的连接方式都各有利弊,到底选择哪种连接方式,取决于客户的数量、客户的分布情况以及怎样发布应用程序。
DCOM是一种最直接的连接方式,它不需要专门的运行期软件支持。不过,Windows 95 不支持DCOM,除非安装了DCOM95程序。
要使用MTS安全服务,最好使用DCOM连接方式。MTS的安全服务是基于角色的,当一个客户通过DCOM访问MTS时,DCOM会告诉MTS有关客户的信息,MTS据此来决定客户的角色。如果用其他连接方式,需要有专门的运行期软件支持,客户的调用首先被传递给这些运行期软件而不是MTS,MTS就不能尽快指派角色。
TCP/IP连接方式的适合范围非常广泛,例如,如果客户程序要以ActiveForm的形式分布在Web上,最好采用TCP/IP连接方式,因为您无法肯定下载ActiveForm的计算机是否支持DCOM,而支持TCP/IP的环境是很普遍的。
要使用TCP/IP连接方式,应用服务器端必须运行一个专门的运行期软件ScktSrver.exe或ScktSrvc.exe,其中,ScktSrvc.exe只适合于Windows NT,可以作为一个服务在后台运行。与DCOM连接方式不同的是,客户的请求首先传递给ScktSrver.exe或ScktSrvc.exe,然后再创建远程数据模块的实例,而不是由客户的调用直接创建远程数据模块的实例。客户程序上的MIDAS连接构件通过IProvider接口与ScktSrvr.exe or ScktSrvc.exe通讯。
不过,客户程序很有可能在没有正常释放对IProvider 接口的引用之前出现异常,而TCP/IP连接方式无法检测到这种情况,更无法通知应用服务器,因此,有可能造成应用服务器上的资源被占用后得不到释放的后果。
如果要在应用服务器端使用Business Object Broker,就要使用OLEnterprise连接方式。此时,应用服务器端和客户端都要安装OLEnterprise运行期软件。
Delphi 4是目前唯一支持CORBA的开发工具。基于CORBA的客户程序和应用服务器可以与其他基于CORBA的应用程序无缝对接。要使用CORBA连接方式,需要ORB的支持,它提供了类似于Business Object Broker的功能。
3.3 创建应用服务器的一般步骤
要创建一个多层Client/Server应用程序,首先要创建应用服务器,然后注册或安装应用服务器,只有应用服务器已注册并且正在运行的情况下,才能创建客户程序。对于客户程序来说,既可以在设计期连接应用服务器,也可以在运行期连接应用服务器。
注意:如果客户程序与应用服务器不在同一个系统中,必须在客户计算机上注册或安装应用服务器,这样,在设计期就可以连接应用服务器。
创建一个应用服务器与创建一个两层的数据库应用程序有些相似,主要的区别是,应用服务器需要提供IProvider接口,这一般是通过TDataSetProvider或TProvider构件提供的,也可以通过数据集构件如TTable的Provider属性提供。创建应用服务器的一般步骤是:
第一步是使用"File"菜单上的"New Application"命令开始一个新项目,然后使用File菜单上的New命令,选取Multi页,如图3.1所示。
选择一个远程数据模块。如果要创建一个COM自动化服务器,允许客户通过DCOM、TCP/IP、OLEnterprise等方式访问此服务器,选择RemoteMod。如果要创建一个允许客户通过MTS访问的Active Library,选择MTSData Module。如果要创建一个CORBA服务器,选择Corba Data。
第二步是把一个数据集构件如TTable、TQuery或TStoredProc放到远程数据模块上,并进行有关设置,使得它们能访问远程的SQL数据库。尽量不要把TDatabase构件放到远程数据模块上,因为这可能引起名称冲突。如果实在要用TDatabase构件来连接SQL数据库,建议把TDatabase构件放到另一个数据模块上,然后引用这个数据模块的单元文件。
第三步是把TDataSetProvider或TProvider构件放到远程数据模块上,有一个数据集构件,就要有一个TDataSetProvider或TProvider构件与之对应。然后,用鼠标右键单击TDataSetProvider或TProvider构件,在弹出的菜单中选择ExportFrom <Name> in Data Module命令,这是为了引出Provider接口,在类型库中注册。
第四步是设置TDataSetProvider或TProvider构件的DataSet属性指定要访问的数据库,实际上就是第二步所放的数据集构件。
第五步是编写代码,实现商业规则。当然,这一步远远不是几句话所能说清楚的。
第六步是保存、编译、注册或安装应用服务器。
如果使用DCOM、TCP/IP、OLEnterprise作为通讯协议,应用服务器就好像一个自动化服务器一样,必须像ActiveX或COM服务器那样注册。
如果使用MTS,应用服务器是DLL而不是EXE,这时候不需要注册应用服务器,而要把这个DLL作为MTS对象安装到MTS包中。
如果使用CORBA,可以不注册但最好注册。如果要使客户程序对服务器接口的调用在运行期是动态确定的,就要在接口库(Interface Repository)中安装服务器的接口。如果要使客户程序能自动激活应用服务器(如果还没有运行的话),应用服务器就必须用OAD(Object Activation Daemon)注册。
第七步是如果应用服务器没有使用DCOM,您必须安装有关的运行期软件,因为其他连接方式需要这些运行期软件的支持。例如,对于TCP/IP来说,需要安装ScktSrvr.exe或ScktSrvc.exe,后者只能运行在Windows NT环境下。对于OLEnterprise来说,需要安装OLEnterprise运行期版本。对于CORBA来说,需要安装VisiBroker ORB。
3.4 远程数据模块
应用服务器的关键部件是远程数据模块。Delphi 4支持三种类型的远程数据模块,分别是TRemoteDataModule、TMTSDataModule、TCorbaDataModule。
3.4.1 TRemoteDataModule
要加入一个TRemoteDataModule类型的远程数据模块,使用“File”菜单上的“New”命令,选取“Multitier”页,双击“Remote Data Module”图标,弹出“Remote Data Module Wizard”对话框,如图3.2所示。
在“Class Name”框内键入远程数据模块的类名,不必以T打头。Delphi 4将以此名生成一个TRemoteDataModule的派生类,并以此名生成有关接口。例如,假如在“Class Name”框内键入“MyDataServer”, 远程数据模块的类名就是TMyDataServer,它所实现的接口叫IMyDataServer,其祖先接口是IDataBroker。
在“Threading Model”框内选择一种线程模式。可以选“Single-threaded”、“Apartment-threaded”、“Free-threaded”或者“Both”。
在“Instancing”框内选择是否根据客户的请求生成远程数据模块的多个实例,可以选“Single instance”或“Multiple instance”。
3.4.2 TMTSDataModule
要加入一个TMTSDataModule类型的远程数据模块,使用“File”菜单上的“New”命令,选择“Multitier”页,双击“MTS Data Module”图标,弹出“MTSData Module Wizard”对话框,如图3.3所示。
图3.3 MTS Data Module对话框
在“Class Name”框内键入远程数据模块的类名,不必以T打头。Delphi 4将以此名生成一个TMTSDataModule的派生类,并以此名生成有关接口。例如, 假设在“Class Name”框内键入“MyDataServer”, 远程数据模块的类名就是TMyDataServer,它所实现的接口叫IMyDataServer,其祖先接口是IDataBroker。
对于TMTSDataModule类型的远程数据模块来说,必须在“ThreadingModel”框内选择一种线程模式。可以选“Single”、“Apartment”或者“Both”。在“Transaction Attributes”框内选择事务属性:
如选择“Requires a transaction”,每当客户访问远程数据模块的接口时,都与当前的事务是相关的。客户不可能在事务中再申请一个新的事务。
如选择“Requires a new transaction”,每当客户访问远程数据模块的接口时,都自动开始一个新的事务。如选择“Supports transactions”,远程数据模块可以用在事务的环境中,客户访问远程数据模块的接口时必须申请一个新的事务。
如选择“Does not support transactions”,远程数据模块不能用在事务的环境中。
注意:MTS对象只能加入到ActiveX项目中,如果试图在一个EXE项目中加入TMTSDataModule类型的远程数据模块,Delphi 4会显示一个提示框,如图3.4所示。
图3.4 一个提示框
3.4.3 TCORBADataModule
要加入一个TCorbaDataModule类型的远程数据模块,使用“File”菜单上的“New”命令,选取“Multitier”页,双击“CORBA Data Module”图标,弹出“CORBA Data Module Wizard”对话框,如图3.5所示。
图3.5 CORBA Data Module对话框
在“Class Name”框内键入远程数据模块的类名,不必以T打头。Delphi 4将以此名生成一个TCorbaDataModule的派生类,并以此名生成有关接口。例如,假设在“Class Name”框内键入“MyDataServer”, 远程数据模块的类名就是TMyDataServer,它所实现的接口叫IMyDataServer,其祖先接口是IDataBroker。
在“Instancing”框内指定应用服务器怎样创建远程数据模块的实例,可以选“Shared Instance”或者“Instance-Per-Client”。
如果选“Shared Instance”,应用服务器只创建远程数据模块的一个实例来处理所有客户的请求,因此,远程数据模块必须与状态无关,换句话说,就是不能使用IProvider接口。
如果选“Instance-Per-Client”,每当一个客户试图连接时,远程数据模块都会生成一个实例。只要客户与应用服务器的连接没有断开,远程数据模块的实例就一直存在。这种模式下,允许使用IProvider接口。唯一要考虑的问题是,客户程序有可能意外终止,导致没有正常地断开与应用服务器的连接。应用服务器为了避免不必要的资源浪费,可以定期地检查客户是否正在运行,如没有,就手工把远程数据模块的实例删掉。
在“Threading Model”框内选择一种线程模式。可以选“Single-threaded”、“Multi-threaded”。
3.5 Provider
远程数据模块上往往要放一个或几个TDataSetProvider或TProvider构件,用于提供IProvider接口。有时候,也可以不显式地使用TDataSetProvider或TProvider构件,而是由数据集构件如TTable、TQuery或TStoredProc的Provider属性间接地提供IProvider接口。
显式地使用TDataSetProvider或TProvider构件的好处是,可以直接控制数据包中包含哪些信息、应用服务器怎样响应客户的请求。如果显式地使用了TDataSetProvider或TProvider构件,必须设置他们的DataSet属性指定要访问的数据集。
3.5.1 控制数据包中的字段
要控制哪些字段包含到数据包中,首先要创建永久字段。以后,只有永久字段才加入到数据包中。如果不创建永久字段的话,数据集中的所有字段都将加入到数据包中。
如果创建的永久字段中包含计算字段,由于计算字段的值是在运行期计算出来的,这些字段虽然也能加入到数据包中,但这些字段传递到客户端后就变成只读的。
由于客户程序很有可能要编辑修改数据,并且要把编辑修改后的数据申请更新到应用服务器上,因此,您创建的永久字段的数量不能太少,否则,很有可能出现重复的记录。举例来说,假设有一个学生成绩表,由学号、姓名、语文成绩、数学成绩、历史成绩等字段组成,如果创建的永久字段中只包含语文成绩、数学成绩、历史成绩等字段,很有可能出现两名学生的上述成绩完全一样,也就是说有重复的记录,这是不允许的。
如果实在不想使客户程序看到某个字段,而如果没有这个字段的话很有可能出现上述错误,这时候您可以让这个字段(TField对象)的ProviderFlags属性包含pfHidden元素,表示这个字段虽然加入到数据包中,但却是隐含的,客户看不到它。
特别要注意的是,如果使用TQuery作为应用服务器上的数据集构件,SQL语句应当选择足够多的字段,即使客户程序并不需要这么多字段,否则,就有可能出现上述错误。
3.5.2 Options属性
这个属性是一个集合,用于设置有关打包和传递的选项。
如果包含poFetchBlobsOnDemand元素,表示BLOB字段一般不放到包中,除非客户端的TClientDataSet构件的FetchOnDemand属性设为True或者显式地调用FetchBlobs。
如果包含poFetchDetailsOnDemand元素,表示嵌套表中的字段不放到包中,除非客户端的TClientDataSet构件的FetchOnDemand属性设为True或者显式地调用FetchDetails。
如果包含poIncFieldProps元素,表示把字段的属性也放到包中,包括Alignment、MinValue、DisplayLabel、DisplayWidth、Visible、DisplayFormat、MaxValue、EditFormat、Currency、EditMask、DisplayValues等属性。
如果包含poCascadeDeletes元素,当父表中的某条记录被删除时就把子表中的相应记录也删除。
如果包含poCascadeUpdates元素,当父表的关键字段的值变化时自动更新子表的记录。
如果包含poReadOnly元素,表示不允许“瘦”客户向TDataSetProvider申请更新数据。
3.5.3 在数据包中加入自定义的信息
当客户端通过IProvider 接口调用DataRequest函数请求数据时将在应用服务器端触发OnGetDataSetPropertiesevent事件,这样,应用服务器就有机会在数据包中加入一些自定义的信息。客户端可以调用GetOptionalParam来检索这些信息。
OnGetDataSetPropertiesevent事件是这样声明的:
TGetDSProps = Procedure(Sender: TObject; DataSet: TDataSet; out Properties:OleVariant);
其中,Properties参数是一个可变类型的数组,用于指定要加入的信息。Properties参数的每个元素由三部分组成:名称、值和一个布尔数。Delphi 4定义了几个标准的信息名称,它们是UNIQUE_KEY、DEFAULT_ORDER、CHANGE_LOG、SERVER_COL、CONSTRAINTS、DATASET_CONTEXT、DATASET_DELTA、LCID、BDERECORD_X、TABLE_NAME、MD_FIELDLINKS、UPDATEMODE。程序示例如下:
Procedure TAppServer.Provider1GetDataSetProperties(Sender: TObject; DataSet: TDataSet; out Properties:OleVariant);
Begin
Properties := VarArrayCreate([0,1], varVariant);
Properties[0] := VarArrayOf(['TimeProvided', Now, True]);
Properties[1] := VarArrayOf(['TableSize', DataSet.RecordCount, False]);
End;
上面这个程序中,加入了两个自定义的信息,一个叫TimeProvided,它的值是当前的日期和时间,True表示这个信息可以由客户端返回给应用服务器。另一个信息叫TableSize,它的值是数据集的记录数,False表示这个信息不可以由客户端返回给应用服务器。
以后,当客户端申请更新数据时,TDataSetProvider的OnUpdateData事件可以读出数据包中的信息。程序示例如下:
Procedure TAppServer.Provider1Updat
参考资料:我使用的是 c/s结构,用delphi+interbase编写《建筑工地管理系统》