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

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

作者:闵涛 文章来源:闵涛的学习笔记 点击数:2894 更新时间:2009/4/23 18:30:21
ection构件,它的ProviderName属性设为Country。
  此外,窗体上有一个栅格用于显示数据集中的数据,还有一个“Open”按钮用于打开数据集。
  由于TDCOMConnection构件的LoginPrompt属性设为True,当客户程序试图连接应用服务器时就会弹出一个“Remote Login”对话框,要求用户输入用户名和口令。登录以后,就触发OnLogin事件。在处理这个事件的句柄中,客户程序通过AppServer属性获得数据模块的接口,从而调用数据模块的Login。
  Procedure TForm1.DCOMConnection1Login(Sender: TObject; Username,Password: String);
Begin
DCOMConnection1.AppServer.Login(UserName, Password);
End;
  在应用服务器的数据模块单元中,Login是这样定义的。
Procedure TLoginDemo.Login(const UserName, Password: WideString);
Begin
Form1.ListBox1.Items.Add(UserName);
FLoggedIn := True;
FUserName := UserName;
End;
  Login把用户名加到列表框中,然后把FLoggedIn变量设为True,表示用户已登录。当用户单击“Open”按钮,就调用TClientDataSet构件的Open打开数据集。
Procedure TForm1.Button1Click(Sender: TObject);
Begin
ClientDataSet1.Open;
End;
14.7 一个演示Master/Detail关系的示范程序
  这一节剖析一个演示Master/Detail关系的示范程序,它可以在C:\ProgramFiles\Borland\Delphi4\ Demos\Midas\Mstrdtl目录中找到。
  这个程序分为应用服务器和客户程序两个部分。应用服务器有一个窗体,不过,这个窗体其实是多余的,如果不想显示,可以打开应用服务器的项目文件,加入这么一行:
  Application.ShowMainForm := False;
  应用服务器的数据模块如图14.19所示。
  应用服务器的数据模块上有这么几个构件:
  名为Database的TDatabase构件,其AliasName属性设为IBLOCAL,并且定义了一个应用程序专用的别名叫ProjectDB。其Params属性提供了用户名和口令。
  名为Project的TTable构件,其DatabaseName属性设为ProjectDB,它的TableName属性设为PROJECT(注意:必须已运行Interbase Server)。
  名为Employee的TQuery构件,其DatabaseName属性设为ProjectDB,它的SQL语句如下:Select * From EMPLOYEE_PROJECT E Where E.PROJ_ID= :PROJ_ID
  名为EmpProj的TQuery构件,其DatabaseName属性设为ProjectDB,它的SQL语句如下:Select EMP_NO,FULL_NAME From EMPLOYEE
  名为UpdateQuery的TQuery构件,其DatabaseName属性设为ProjectDB,它的SQL语句目前是空的。
  名为ProjectProvider的TProvider构件,其DataSet属性设为Project。
  名为ProjectSource的TDataSource构件,其DataSet属性设为Project。编译并运行应用服务器。现在可以打开客户程序的项目,它的数据模块如图14.20所示。
  图14.20 数据模块
  客户程序的数据模块上有这么几个构件:
  名为DCOMConnection的TDCOMConnection构件,其ServerName属性设为Serv.ProjectData。
  名为Project的TClientDataSet构件,其RemoteServer属性设为DCOMConnection它的ProviderName属性设为ProjectProvider。并且建立了一个叫ProjectEmpProj的永久字段对象,它的类型是TDataSetField。与Project对应的TDataSource构件叫ProjectSource。
  名为Emp_Proj的TClientDataSet构件,其RemoteServer属性和ProviderName属性都是空的,但它的DataSetField属性设为叫ProjectEmpProj的字段对象,这就构成了Master/Detail关系。与Emp_Proj对应的TDataSource构件叫EmpProjSource。
  名为Employee的TClientDataSet构件,其RemoteServer属性指定了TDCOMConnection构件,但它的ProviderName属性设为Employee。与Employee对应的TDataSource构件叫EmployeeSource。
  我们再来看客户程序的主窗体,如图14.21所示。
  左边一个栅格只显示Project数据集中的PROJ_NAME字段即项目名称,“Product”框显示Project数据集中的PRODUCT字段,“Description”框显示Project数据集中的PROJ_DESC字段,并且用一个TDBNavigator构件为Project数据集导航。
  右下角的栅格显示Emp_Proj数据集中一个叫EmployeeName的字段的值,这是个Lookup字段,它的LookupDataSet属性设为Employee,它的LookupKeyField属性设为EMP_NO,它的LookupResultField属性设为FULL_NAME。当用户用导航器浏览Project数据集的记录时,右下角的栅格就从Employee数据集中查找与EMP_NO字段匹配的记录,并且显示其中的FULL_NAME字段。
  由于右下角的栅格只建立了一个永久的列对象,因此,可以把这一列的宽度设为与栅格本身同宽,它是在处理窗体的OnCreate事件的句柄中进行的。
Procedure TClientForm.FormCreate(Sender: TObject);
Begin
MemberGrid.Columns[0].Width :=MemberGrid.ClientWidth - GetSystemMetrics(SM_CXVSCROLL);
End;
  由于一个项目中不止一个雇员,为了醒目起见,可以把其中的负责人加粗显示,这需要处理栅格的OnDrawColumnCell事件。
Procedure TClientForm.MemberGridDrawColumnCell(Sender: TObject; const Rect: TRect;DataCol: Integer;Column: TColumn;State: TGridDrawState);
Begin
If DM.ProjectTEAM_LEADER.Value = DM.Emp_ProjEMP_NO.Value then MemberGrid.Canvas.Font.Style := [fsBold];
MemberGrid.DefaultDrawColumnCell(Rect, DataCol, Column, State);
End;
  怎样来判断其中的负责人呢?在Project数据集中,有一个TEAM_LEADER 字段,它存储的是项目负责人的雇员编号。在Emp_Proj数据集中,有一个EMP_NO,它存储的也是雇员编号,如果这两者相等,即表示该雇员是项目负责人。当用户单击“Add”按钮,就可以在栅格中增加一条记录,即在项目中增加一个雇员。
Procedure TClientForm.AddBtnClick(Sender: TObject);
Begin
MemberGrid.SetFocus;
DM.Emp_Proj.Append;
MemberGrid.EditorMode := True;
End;
  由于栅格事先建立了一个永久的列对象,而该列对象的FieldName属性指定了一个Lookup字段,所以,用户可以从一个组合框中选择一个值。
  当用户单击“Delete”按钮,就删除当前记录,即一个雇员。
Procedure TClientForm.DeleteBtnClick(Sender: TObject);
Begin
DM.Emp_Proj.Delete;
End;
  当用户先选择其中一个雇员,然后单击“Leader”按钮,就把该雇员设为项目负责人。
Procedure TClientForm.LeaderBtnClick(Sender: TObject);
var NewLeader: Integer;
Begin
NewLeader := DM.Emp_ProjEMP_NO.Value;
If not (DM.Project.State in dsEditModes) then DM.Project.Edit;
DM.ProjectTEAM_LEADER.Value := NewLeader;
MemberGrid.Refresh;
End;
  增加、删除或修改了记录后,用户应当单击“Apply Update”按钮更新数据库。
Procedure TClientForm.ApplyUpdatesBtnClick(Sender: TObject);
Begin
DM.ApplyUpdates;
End;
  在数据模块的单元中,ApplyUpdates是这样定义的:
Procedure TDM.ApplyUpdates;
Begin
If Project.ApplyUpdates(0) = 0 then Project.Refresh;
End;
  可以看出,数据模块的ApplyUpdates又调用了TClientDataSet构件的ApplyUpdates,并且把MaxErrors参数设为0,这样,只要应用服务器发现有一个错误的记录,更新就停止。
  当用户在左边的栅格中试图增加一个新的项目时,会触发TClientDataSet构件的OnNewRecord事件。由于这个栅格只显示了PROJ_NAME字段,用户不能直接输入PROJ_ID字段的值,因此,程序在处理OnNewRecord事件的句柄中推出一个输入框,让用户输入PROJ_ID字段的值。如果用户输入的字符超过了该字段允许的长度,就触发一个异常。
  如果用户没有输入任何字符,也触发一个异常。
Procedure TDM.ProjectNewRecord(DataSet: TDataSet);
va rValue: String;
Begin
If InputQuery(''''Project ID'''',''''Enter Project ID:'''',Value) then
Begin
If Length(Value) > ProjectPROJ_ID.Size then
Raise Exception.CreateFmt(''''Project ID can only be %d characters'''',[ProjectPROJ_ID.Size]);If Length(Value) = 0 then
Raise Exception.Create(''''Project ID is required'''');
End
Else
SysUtils.Abort;
ProjectPROJ_ID.Value := Value;
End;
  由于Project数据集与Employee数据集之间存在着Master/Detail关系,当删除Project数据集的一条记录时,应当先删除Employee数据集中关联的记录。应用服务器利用TProvider构件的BeforeUpdateRecord事件实现了这一点。
Procedure TProjectData.ProjectProviderBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet;DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean);
Const DeleteQuery = ''''Delete From EMPLOYEE_PROJECT where PROJ_ID = :ProjID'''';
Begin
If (UpdateKind = ukDelete) and (SourceDS = Project) then
Begin
UpdateQuery.SQL.Text := DeleteQuery;
UpdateQuery.Params[0].AsString := DeltaDS.FieldByName(''''PROJ_ID'''').AsString;
UpdateQuery.ExecSQL;
End;
End;
14.9 一个动态设置查询参数的示范程序
  这一节剖析一个动态设置查询参数的示范程序,它可以在C:\ProgramFiles\Borland\Delphi4\ Demos\ Midas\Setparam目录中找到。
  这个程序分为应用服务器和客户程序两个部分。当客户程序通过TClientDataSet构件的Params属性设置参数时,这些参数会自动地传递给应用服务器上的TQuery构件,这样就能够根据用户的要求来查询数据库,这就是本示范程序的基本思路。
  我们来剖析应用服务器,先看它的数据模块,如图14.24所示。图14.24 数据模块数据模块上只有一个TQuery构件,它的DatabaseName属性设为DBDEMOS,它的SQL语句如下:
  Select * From EventsWhere Event_Date >= :Start_Date and Event_Date <= :End_Date Order by Event_Date
  可以看出,这个SQL语句中有两个参数,一个是:Start_Date,另一个是:End_Date。
  现在我们暂时不管数据模块,再来看看应用服务器的主窗体,如图14.25所示。
  图14.25 应用服务器的主窗体
  主窗体上显示两个计数,一个是当前连接应用服务器的客户数(Clients),另一个是已经执行的查询次数(Queries)。用什么来判断当前的客户数,这与数据模块的实例方式有关。我们可以回到数据模块的单元,看看它的初始化代码:
Initialization
TComponentFactory.Create(ComServer, TSetParamDemo,
Class_SetParamDemo, ciMultiInstance);
End.
  可以看出,这个数据模块的实例方式设为ciMultiInstance,表示每当有一个客户连接应用服务器,就会创建数据模块的一个新的实例。因此,数据模块的实例数就是当前的客户数。怎样统计数据模块的实例数呢?很简单,只要处理数据模块的OnCreate事件。
Procedure TSetParamDemo.SetParamDemoCreate(Sender: TObject);
Begin
MainForm.UpdateClientCount(1);
End;
  当一个客户退出连接,将删除一个数据模块的实例,此时将触发数据模块的OnDestroy事件:
Procedure TSetParamDemo.SetParamDemoCreate(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 TSetParamDemo.EventsAfterOpen(DataSet: TDataSet);
Begin
MainForm.IncQueryCount;
End;
  IncQueryCount是在主窗体的单元中定义的:
Procedure TMainForm.IncQueryCount;
Begin
Inc(FQueryCount);
QueryCount.Caption := IntToStr(FQueryCount);
End;
  编译和运行这个应用服务器。打开客户程序的项目,它的主窗体如图14.26所示。
  窗体上有一个TDCOMConnection构件用于连接应用服务器,有一个叫Events的TClientDataSet构件,用于引入数据集。
  “Starting Date”框用于输入:Start_Date参数的值,
  “Ending Date”框用于输入:End_Date参数的值。中间的栅格用于显示查询的结果。“Description”框用于显示Event_Description字段的值。“Photo”框用于显示Event_Photo字段的值。
  客户程序在处理窗体的OnCreate事件的句柄中对“Starting Date”框和“EndingDate”框进行初始化。
Procedure TForm1.FormCreate(Sender: TObject);
Begin
StartDate.Text := DateToStr(EncodeDate(96, 6, 19));
EndDate.Text := DateToStr(EncodeDate(96, 6, 21));
End;
  用户可以在这两个框中重新输入其他日期,然后单击“Show Events”按钮。
Procedure TForm1.ShowEventsClick(Sender: TObject);
Begin
Events.Close;
Events.Params.ParamByName(''''Start_Date'''').AsDateTime:=StrToDateTime(StartDate.Text);Events.Params.ParamByName(''''End_Date'''').AsDateTime :=StrToDateTime(EndDate.Text);
Events.Open;
End;
  首先,要调用TClientDataset构件的Close关闭数据集,然后分别设置Start_Date参数和End_Date参数的值,最后,调用TClientDataset构件的Open打开数据集,此时,这两个参数就被自动传递给应用服务器上的TQuery构件。

上一页  [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……
    咸宁网络警察报警平台