步骤2 建立范例应用程序的主窗体
回到范例应用程序的主窗体,在其中放入TDataSource,并且设定它的DataSet属性值为步骤1建立的cdsBooks控件(注:读者必须在主窗体中先use步骤1的数据模块,即点击File|Use Unit…选项,选择步骤1的dmDemo1数据模块),再放入TDBNavigator和TDBGrid控件,设定它们的DataSource属性值为刚才加入的TDataSource。最后在主窗体下方放入一个TPanel控件,此时范例主窗体看起来如图2-5所示。

图2-5 范例应用程序的主窗体
现在我们希望当用户浏览一本书籍时,能够同时显示出版这本书的出版商信息,因此我们需要显示PUBLISHERS数据表中的数据。请打开数据模块,双击scdsPublishers控件以启动它的字段编辑器,接着把PUBLISHERS数据表的所有字段对象拖曳到刚才加入的TPanel控件之中。此时主窗体如图2-6所示。

图2-6 在主窗体中加入显示scdsPublishers字段的数据感知控件
接下来的工作就是实现此范例应用程序,它需要的功能就是当用户移动书籍数据时,把出版此书的出版商信息显示在下方的数据感知控件之中。
步骤3 实现范例应用程序
要实现浏览书籍时同时显示出版商信息的功能,那么我们首先需要根据目前正被浏览的书籍的出版商编号到PUBLISHERS数据表中查寻。而在前面建立数据模块时cdsPublishers控件的SQL语句正是根据出版商编号从PUBLISHERS数据表中取得的数据,因此我们只需要把目前正被浏览的书籍的出版商编号传递给cdsPublishers控件即可。进行这项工作的好处是当用户移动目前的记录位置到其他记录时,我们可以在cdsBooks的AfterScroll事件处理函数中进行这项工作。
请在数据模块中点击cdsBooks,双击它的AfterScroll事件,并且撰写如下的程序代码:
procedure TdmDemo1.cdsBooksAfterScroll(DataSet: TDataSet);
begin
try
Self.cdsPublishers.Active := False;
Self.cdsPublishers.Params.ParamByName('VID').AsString :=
Self.cdsBooks.FieldByName('VID').AsString;
Self.cdsPublishers.Active := True;
except
on ex : Exception do
ShowMessage(ex.Message);
end;
end;
上面的程序代码首先把目前书籍的出版商ID传入到cdsPublishers定义的动态参数之中。这样我们只需要存取cdsPublishers的DataSet.Params属性,再调用DataSet.Params返回对象TParam的ParamByName方法即可。最后打开cdsPublishers,即可取得正确的出版商数据。
步骤4 执行范例应用程序
现在就可以编译并且执行范例应用程序了,图2-7就是范例应用程序此时的执行画面。当用户使用窗体上方的TDBNavigator移动数据时,下方显示出版商的数据感知控件便会显示出正确的出版商数据。
现在我们已经使用dbExpress控件和动态SQL语句的方式顺利地取得范例应用程序需要的数据了。接着让我们观察dbExpress如何处理变更的数据。

图2-7 执行范例应用程序的画面
步骤5 取得目前被变更的数据笔数信息
回到主窗体,在窗体中加入一个TBitBtn控件,设定它的Caption属性值为“ApplyUpdates”。再加入一个TStatusBar控件,双击它并且加入一个新的TStatusPanel控件。接着我们希望主窗体也能够显示书籍的作者名称,因此另外在主窗体中加入一个TLabel控件,设定它的Caption属性值为“作者”,再加入一个TDBEdit控件,此时范例主窗体应该有如图2-8所示的画面。

图2-8 在范例应用程序的主窗体中加入TBitBtn控件和TStatusBar控件
要在主窗体中显示书籍的作者,我们也需要在书籍被浏览时到PERFORMERS数据表中查寻数据,因此请打开数据模块,在数据模块中再加入一个TSQLQuery控件,设定它的DBConnection属性值为scnnDemo,设定它的Name属性值为quryAuthor。此时数据模块如图2-9所示。

图2-9 在数据模块中加入TSQLQuery控件,设定Name属性值为quryAuthor
使用TSQLQuery控件的原因是我们只想显示作者的名称,不想变更作者名称的信息,而又需要使用SQL语句来根据目前书籍的信息来查寻到作者,因此使用TSQLQuery控件不但可以使用SQL语句,而且,更重要的是对于只读的数据,使用TSQLQuery控件比使用另外一组TDataSetProvider/TClientDataSet控件要有效率得多了。
接着在前面已经讨论过的AfterScroll事件处理函数中加入一行调用GetAuthor的程序代码:
procedure TdmDemo1.cdsBooksAfterScroll(DataSet: TDataSet);
begin
try
Self.cdsPublishers.Active := False;
Self.cdsPublishers.Params.ParamByName('VID').AsString :=
Self.cdsBooks.FieldByName('VID').AsString;
Self.cdsPublishers.Active := True;
GetAuthor;
except
on ex : Exception do
ShowMessage(ex.Message);
end;
end;
而GetAuthor方法则使用了动态组成SQL语句的方式从PERFORMERS数据表中取得数据。下面的程序代码很简单,它从cdsBooks中取得书籍作者的ID,再借助这个ID组成SQL语句从PERFORMERS数据表中取得正确的数据。
procedure TdmDemo1.GetAuthor;
begin
Self.quryAuthor.Active := False;
Self.quryAuthor.SQL.Text :=
'select * from PERFORMERS where AID = ' + '''' +
Self.cdsBooks.FieldByName('AID').Value + '''';
Self.quryAuthor.Active := True;
end;
现在再执行范例应用程序,我们便可以在主窗体中看到书籍作者的数据了。
在这里本书只是展示开发人员也可以使用动态组成SQL的方式来存取数据,quryAuthor就是一个范例。但是在这里的程序代码并不是很好的,因为它的执行效率并不好。如果读者使用前面和cdsPublishers一样的动态参数方法会比较有效率,因为在quryAuthor的SQL语句中只有作者ID会改变。
在前面本书说过当用户在应用程序中变更了数据后,这些变更的数据会暂时储存在TSimpleDataSet/TClientDataSet的Delta属性值之中。开发人员可以借助存取TSimpleDataSet/TClientDataSet的控件ChangeCount属性值来得知目前已经被变更的数据笔数,并且可以根据这个数值来决定是否需要调用ApplyUpdates方法,把变更的数据真正地更新回后端数据源中。现在就让我们在范例应用程序中显示目前被变更的数据笔数。
当TSimpleDataSet/TClientDataSet调用Post方法把变更数据暂时储存在Delta属性值之中后,它的ChangeCount属性值便会随着更新。因此要得知目前的变更数据笔数,我们可以在cdsBooks的AfterPost事件处理函数中显示ChangeCount。请点击数据模块中的cdsBooks,并且在它的AfterPost事件中撰写如下的程序代码:
procedure TdmDemo1.cdsBooksAfterPost(DataSet: TDataSet);
begin
frmMain.ShowChangeCount(cdsBooks.ChangeCount);
end;
上面的程序代码调用了主窗体中的ShowChangeCount方法来显示变更数据的笔数。
接着回到主窗体中双击ApplyUpdates按钮并且在OnClick事件中撰写如下的程序代码。当cdsBooks调用ApplyUpdates方法之后也调用ShowChangeCount方法再次显示当数据真正被更新回数据源之后客户端暂时内存Delta属性值的改变状态。
procedure TfrmMain.BitBtn1Click(Sender: TObject);
begin
dmDemo1.cdsBooks.ApplyUpdates(0);
ShowChangeCount(dmDemo1.cdsBooks.ChangeCount);
end;
最后是ShowChangeCount方法的实现,它只是存取cdsBooks的ChangeCount属性值并且显示在主窗体的TStatusBar控件之中:
procedure TfrmMain.ShowChangeCount(const iCount : Integer);
begin
StatusBar1.Panels[0].Text :=
'目前被变更的数据笔数:' +
IntToStr(dmDemo1.cdsBooks.ChangeCount);
end;
现在编译并且执行范例应用程序,图2-10是执行范例应用程序并且更新两笔数据之后的画面。从TStatusBar控件中可以看到ChangeCount属性值正确地记录了目前有2笔数据在客户端被变更了。

图2-10 执行范例应用程序并且变更数据
接着我们点击窗体中的【ApplyUpdates】按钮,调用ApplyUpdates方法把数据真正地更新回数据源中。图2-11显示了当ApplyUpdates方法成功地执行完毕之后,客户端记录的暂时变更数据笔数也清除为0了。
到目前为止,本范例展示了如何使用dbExpress控件存取数据以及使用动态SQL在应用程序执行时动态选择应用程序需要的数据。读者现在应该能够使用dbExpress控件来处理基本数据了。接下来让我们继续以这个范例应用程序来讨论重要的Data和Delta属性。

图2-11 范例应用程序调用ApplyUpdates方法后的画面






