百度空间 | 百度首页 
               
 
查看文章
 
多层数据库开发(十四)---:剖析几个MIDAS示范程序
2008-09-03 17:40
第十四章 剖析几个MIDAS示范程序
  MIDAS是Multi-Tier Distributed Application Services Suite的简称,为Delphi 4的一个关键技术。对于初学者来说,MIDAS具有相当的难度,因此,这一章详细剖析几个MIDAS示范程序,以帮助读者理解和掌握MIDAS技术。
  与一般的数据库应用程序不同的是,只有当应用服务器正在运行的情况下,才能打开、编译和运行“瘦”客户程序的项目。
14.1 一个ActiveForm的例子
  Delphi 4可以把分布式的数据库结构引申到Internet/Intranet上,把“瘦”客户程序作为ActiveForm嵌入到网页中让人们下载,然后在当地执行。
  这一节剖析一个ActiveForm的示范程序,项目名称叫empeditx,它可以在C:Program FilesBorlandDelphi4DemosMidasActivefm目录中找到。它的主窗体如图14.1所示。
  在打开这个项目之前,先要编译、运行位于C:ProgramFilesBorlandDelphi4Demos MidasEmpedit目录中的Server项目,这是个应用服务器,如图14.2所示。
  这里还要交代一下,在应用服务器上,用一个TQuery构件引入数据集,它的SQL语句如下:
  Select * From Employee
  在这个ActiveForm上,有一个TDCOMConnection构件,用于以DCOM方式连接应用服务器,它的ServerName属性设为Serv.EmpServer,它的ServerGUID设为{53BC6562-5B3E-11D0-9FFC-00A0248E4B9A}。
  ActiveForm用TClientDataSet构件从应用服务器引入数据集,它的RemoteServer属性设为MidasConnection即TDCOMConnection构件的名称,它的ProviderName属性设为EmpQuery即应用服务器上的TQuery构件,由它来提供IProvider接口。
  ActiveForm上有几个数据控件,用于显示数据,它们都通过一个TDataSource构件获得数据。此外,ActiveForm上还有一个TDBNavigator构件,用于浏览数据集。
  由于本节要介绍的示范程序是一个ActiveForm,它的大部分代码与类型库有关,我们只把其中涉及到MIDAS技术的部分“拎”出来。
  当用户单击ActiveForm上的“Get Employees”按钮时,就从应用服务器检索数据。每次检索到的记录数取决于TClientDataSet构件的PacketRecords属性。
Procedure TEmpEditForm.QueryButtonClick(Sender: TObject);
Begin
Employees.Close;
{ Employees是TClientDataSet构件的名称}E
mployees.Open;
End;
  当用户单击ActiveForm上的“Update Employees”按钮时,把用户对数据的修改写到数据集中。
Procedure TEmpEditForm.UpdateButtonClick(Sender: TObject);
Begin
Employees.ApplyUpdates(-1);
End;
  当用户单击ActiveForm上的“Undo Last Change”按钮时,取消用户对数据的修改。
Procedure TEmpEditForm.UndoButtonClick(Sender: TObject);
Begin
Employees.UndoLastChange(True);
End;
  为了测试这个ActiveForm,首先需要把它发布到Web服务器上,供下载用。为此,要使用“Project”菜单上的“Web Deployment Options”命令设置有关Web发布的选项,主要是指定ActiveForm在Web服务器上的URL。然后使用“Project”菜单上的“WebDeploy”命令把ActiveForm发布到Web服务器上。
14.2 一个动态传递SQL语句的示范程序
  这一节要剖析一个动态传递SQL语句的示范程序,可以在C:Program FilesBorlandDelphi4DemosMidasAdhoc目录中找到。
  这个程序分为应用服务器和客户程序两个部分。当客户程序通过IProvider接口调用DataRequest请求数据时,把用户输入的SQL语句传递给应用服务器,这样,应用服务器上的TQuery构件就能够根据用户的要求来查询数据库,这就是本示范程序的基本思路。
  先来剖析应用服务器,看它的数据模块,如图14.3所示。
  图14.3 数据模块
  数据模块上有这么几个构件:
  一个TSession构件,它的SessionName属性设为Session1_2。
  一个TDatabase构件,它的SessionName属性设为Session1_2,并且定义了一个专用的别名叫ADHOC。
  一个TQuery构件,它的DatabaseName属性设为ADHOC,它的SessionName属性也设为Session1_2,而它的SQL属性为空,因为SQL语句由客户程序动态地传递过来。
  一个TProvider构件,它的DataSet属性设为AdHocQuery即TQuery构件的名称。
  现在我们暂时不管数据模块,再来看看应用服务器的主窗体,如图14.4所示。
  图14.4 应用服务器的主窗体
  主窗体上显示两个计数,一个是当前连接应用服务器的客户数(Clients),另一个是已经执行的查询次数(Queries)。
  用什么来判断当前的客户数,这与数据模块的实例方式有关。我们可以回到数据模块的单元,看看它的初始化代码:
Initialization
TComponentFactory.Create(ComServer, TAdHocQueryDemo,
Class_AdHocQueryDemo, ciMultiInstance);
End.
  可以看出,这个数据模块的实例方式设为ciMultiInstance,表示每当有一个客户连接应用服务器,就会创建数据模块的一个新的实例。因此,数据模块的实例数就是当前的客户数。怎样统计数据模块的实例数呢?很简单,只要处理数据模块的OnCreate事件。
Procedure TAdHocQueryDemo.AdHocQueryDemoCreate(Sender: TObject);
Begin
MainForm.UpdateClientCount(1);
End;
  当一个客户退出连接时,将删除一个数据模块的实例,此时将触发数据模块的OnDestroy事件:
Procedure TAdHocQueryDemo.AdHocQueryDemoDestroy(Sender: TObject);
Begin
MainForm.UpdateClientCount(-1);
End;
  其中,UpdateClientCount函数是在主窗体的单元中定义的:
Procedure TMainForm.UpdateClientCount(Incr: Integer);
Begin
FClientCount := FClientCount + Incr;
ClientCount.Caption := IntToStr(FClientCount);
End;
  请读者注意Incr参数的作用。怎样统计已经执行过的查询数呢?很简单,只要统计TQuery构件被激活的次数就可以了。因此,程序处理了TQuery构件的AfterOpen事件。Procedure TAdHocQueryDemo.AdHocQueryAfterOpen(DataSet: TDataSet);
Begin
MainForm.IncQueryCount;
End;
  IncQueryCount是在主窗体的单元中定义的:
Procedure TMainForm.IncQueryCount;
Begin
Inc(FQueryCount);
QueryCount.Caption := IntToStr(FQueryCount);
End;
  在打开客户程序的项目之前,必须先编译和运行应用服务器的项目。好,现在我们打开客户程序的项目,它的主窗体如图14.5所示。
  这个客户程序用一个TDCOMConnection构件连接应用服务器,它的ServerName属性设为Serv.AdHocQueryDemo。客户程序用TClientDataSet构件从应用服务器引入数据集,它的RemoteServer属性设为TDCOMConnection构件的名称,它的ProviderName属性设为AdHocQuery,这是应用服务器输出的 IProvider接口。
  客户程序上有一个栅格,用于显示数据,栅格与数据集之间通过TDataSource构件连接。此外,客户程序上有一个多行文本编辑器,让用户输入SQL语句。有一个组合框用于选择要访问的数据库。我们还是先从处理OnCreate事件的句柄开始。
Procedure TForm1.FormCreate(Sender: TObject);
var I: Integer;DBNames: OleVariant;
Begin
RemoteServer.Connected := True;
DBNames := RemoteServer.AppServer.GetDatabaseNames;
If VarIsArray(DBNames) then
For I := 0 to VarArrayHighBound(DBNames, 1) Do
DatabaseName.Items.Add(DBNames[I]);
DatabaseNameClick(Self);
End;
  首先,把TDCOMConnection构件的Connected属性设为True,将连接应用服务器。TDCOMConnection构件的AppServer属性将返回应用服务器上数据模块的接口,通过此接口就可以调用远程数据模块的方法,例如GetDatabaseNames。GetDatabaseNames是在应用服务器的数据模块单元中定义的:
Function TAdHocQueryDemo.GetDatabaseNames: OleVariant;
var I: Integer;
DBNames: TStrings;
Begin
DBNames := TStringList.Create;
Try
Session1.GetDatabaseNames(DBNames);
Result := VarArrayCreate([0, DBNames.Count - 1], varOleStr);
For I := 0 to DBNames.Count - 1 DoResult[I] := DBNames[I];
FinallyDBNames.Free;
End;
End;
  GetDatabaseNames函数的作用是返回一个数组,该数组由所有已定义的别名和BDE会话期对象专用的别名组成。现在我们回到客户程序中,调用了数据模块的GetDatabaseNames函数后,就把检索到别名加到窗体右上角的组合框中,然后调用DatabaseNameClick函数。
Procedure TForm1.DatabaseNameClick(Sender: TObject);
var Password: string;
Begin
If DatabaseName.Text <> '' then
Begin
ClientData.Close;
Try
RemoteServer.AppServer.SetDatabaseName(DatabaseName.Text, '');
Except
On E: Exception DoIf E.Message = 'Password Required' then
Begin
If InputQuery(E.Message, 'Enter password', Password) then
RemoteServer.AppServer.SetDatabaseName(DatabaseName.Text, Password);
End
Else
Raise;
End;
End;
End;
  调用DatabaseNameClick的目的是使应用服务器与另一个数据库连接,这就需要通过AppServer属性获得数据模块的接口,然后调用数据模块单元的SetDatabaseName。SetDatabaseName是在应用服务器的数据模块单元中定义的:
Procedure TAdHocQueryDemo.SetDatabaseName(const DBName, Password: WideString);
Begin
Try
Database1.Close;
Database1.AliasName := DBName;
If Password <> ''

类别:多层开发 | 添加到搜藏 | 浏览() | 评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu