转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 软件开发 >> Delphi程序 >> 正文
多层数据库开发十四:剖析几个MIDAS示范程序         ★★★★

多层数据库开发十四:剖析几个MIDAS示范程序

作者:闵涛 文章来源:闵涛的学习笔记 点击数:2884 更新时间:2009/4/23 18:30:21
                               第十四章 剖析几个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 Files\Borland\Delphi4\Demos\Midas\Activefm目录中找到。它的主窗体如图14.1所示。
  在打开这个项目之前,先要编译、运行位于C:\ProgramFiles\Borland\Delphi4\Demos\ Midas\Empedit目录中的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 Files\Borland\Delphi4\Demos\Midas\Adhoc目录中找到。
  这个程序分为应用服务器和客户程序两个部分。当客户程序通过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 <> '''''''' then
  Database1.Params.Values[''''PASSWORD''''] := Password;
Database1.Open;
Except
{如果数据库打开失败,很可能是因为该数据库需要口令}
On E: EDBEngineError DoIf (Password = '''''''') then Raise Exception.Create(''''Password Required'''')Else
Raise;
End;
End;
  SetDatabaseName的作用是修改TDatabase构件的AliasName属性,然后连接新的数据库,如果失败,就触发一个异常。在客户程序的DatabaseNameClick过程中,如果出现异常,就弹出一个输入框,让用户输入口令,然后再次调用数据模块的SetDatabaseName。
  当用户在“Query”框中输入了SQL语句,就可以单击“Run Query”按钮执行这个查询。问题是,只有应用服务器才可以执行查询,那么客户程序是怎样把SQL语句传递给应用服务器的呢?这就是本示范程序的关键之处。
Procedure TForm1.RunButtonClick(Sender: TObject);
Begin
ClientData.Close;
ClientData.Provider.DataRequest(SQL.Lines.Text);
ClientData.Open;
End;
  原来,客户程序通过IProvider接口调用DataRequest把用户输入的SQL语句传递给应用服务器。客户程序通过IProvider接口调用DataRequest将在应用服务器端触发OnDataRequest事件,我们来看看应用服务器是怎样处理OnDataRequest事件的。
Function TAdHocQueryDemo.AdHocProviderDataRequest(Sender: TObject; Input: OleVariant): OleVariant;
Begin
AdHocQuery.SQL.Text := Input;
End;
  至此,一个动态传递SQL语句的示范程序剖析完毕,请读者仔细琢磨其中的编程技巧。实际上,通过IProvider接口调用DataRequest可以传递任何信息。
14.4 一个全面演示TClientDataSet功能的示范程序
  这一节介绍一个演示TClientDataSet功能的示范程序,项目名称叫Alchtest,它可以在C:\Program Files\Borland\Delphi4\Demos\Midas\Alchtest目录中找到,主窗体如图14.6所示。
  这个程序的总体思路是,用一个多页控件让用户修改TClientDataSet的属性或者调用它的方法,然后在下面的TAB控件中演示修改后的效果。
  程序首先在处理OnCreate事件的句柄中做了一些初始化的工作。
Procedure TDBClientTest.FormCreate(Sender: TObject);
var I: Integer;
Begin
Database1.Close;
FMaxErrors := -1;
FPacketRecs := -1;
SetCurrentDirectory(PChar(ExtractFilePath(ParamStr(0))));
For I := 0 to StatusBar.Panels.Count - 1 do
StatusBar.Panels[I].Text := '''''''';
Application.OnIdle := ShowHeapStatus;
Application.OnHint := OnHint;
StreamSettings(False);
SetEventsVisible(ViewEvents.Checked);
End;
  其中,指定ShowHeapStatus作为处理应用程序的OnIdle事件的句柄,指定OnHint作为处理应用程序的OnHint事件的句柄。ShowHeapStatus是这样定义的:
Procedure TDBClientTest.ShowHeapStatus(Sender: TObject; var Done: Boolean);
Begin
Caption := Format(''''Client DataSet Test Form - (Blocks=%d Bytes=%d)'''',[AllocMemCount, AllocMemSize]);
End;
  ShowHeapStatus的作用是在应用程序空闲的时候,在主窗口的标题栏显示堆的状态,其中,AllocMemCount是当前分配的内存块数,AllocMemSize是当前分配的内存总长度。
  OnHint是这样定义的:
Procedure TDBClientTest.OnHint(Sender: TObject);
Begin
StatusMsg := Application.Hint;
End;
  StatusMsg是一个自定义的属性,用于表达要在状态栏上显示的提示信息。
  在处理OnCreate事件的句柄中还调用了StreamSettings函数。StreamSettings是非常有用的,当窗体关闭时,就调用StreamSettings把窗体上一些控件的状态保存到一个配置文件中。当窗体弹出时,就调用StreamSettings读取配置文件以初始化窗体上的控件。
Procedure TDBClientTest.StreamSettings(Write: Boolean);
Procedure WriteStr(const OptName, Value: string);
Begin
FConfig.WriteString(''''Settings'''', OptName, Value);
End;

Procedure WriteBool(const OptName: string; Value: Boolean);
Begin
FConfig.WriteBool(''''Settings'''', OptName, Value);
End;

Function ReadStr(const OptName: string): string;
Begin
Result := FConfig.ReadString(''''Settings'''', OptName, '''''''');
End;

Function ReadBool(const OptName: string): Boolean;
Begin
Result := FConfig.ReadBool(''''Settings'''', OptName, False);
End;

Function FindPage(const PageName: string): TTabSheet;
var I: Integer;
Begin
For I := AreaSelector.PageCount - 1 downto 0 do
Begin
  Result := AreaSelector.Pages[

[1] [2] [3] [4]  下一页


[Delphi程序]Delphi5.5的MIDAS编程(客户端)  [Delphi程序]Delphi中MIDAS前台程序如何连到后台(MIDAS之五)
[Delphi程序]Delphi中MIDAS线程模型种类(MIDAS之四)  [Delphi程序]Delphi中MIDAS程序的实例化模型种类(MIDAS之三)
[Delphi程序]Delphi中创建MIDAS服务器并注册(MIDAS之二)  [Delphi程序]Delphi中MIDAS是什么(MIDAS之一)
[Delphi程序]Delphi中MIDAS如何控制前台权限(MIDAS之六)  
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · C语言系列  · VB.NET程序
    · JAVA开发  · Delphi程序
    · 脚本语言
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台