3.3 使用计算字段(Calculated Field)
Delphi 2006为客户端的数据集提供了计算字段的功能以方便程序员在撰写应用程序时创建临时字段。所谓计算字段是指在许多的数据库应用程序中,经常需要使用一些临时的字段来储存一些数值,以方便应用程序进行计算的工作。由于这些字段只是在应用程序执行时帮助应用程序完成工作的需要,而不用永久储存在数据库中。对于此类的应用,计算字段便是很好的解决方案。
由于DataSnap原本就是在客户端的内存中建立数据集架构的,因此,DataSnap当然也可以在这个内存架构中建立额外的不存在于数据表中的临时字段。Delphi 2006提供了方便的UI和事件处理函数来帮助程序员使用计算字段来解决数据库应用程序的需求。在UI方面,程序员可以通过启动数据集控件的字段编辑器来加入任何数目的计算字段,而且能够建立任何类型的字段。另外数据集的AutoCalcFields特性值可以控制计算字段的执行行为,OnCalcFields事件处理函数则是程序员使用计算字段的地方。在OnCalcFields事件处理函数中,程序员可以使用Object Pascal程序代码来为计算字段进行任何的计算行动。OnCalcFields事件处理函数声明成如下的原型:
type TDataSetNotifyEvent = procedure(DataSet: TDataSet) of object;
其中参数DataSet是指触发此事件的数据集,也就是拥有此计算字段的数据集。
由于计算字段的弹性非常大,因为程序员可以定义任何数目和类型的计算字段,又可以使用Object Pascal在OnCalcFields事件处理函数中进行任何的计算工作,因此,计算字段在许多的数据库应用程序中都通常被使用。而在Delphi中使用计算字段非常地简单,只需要完成下面的两个操作即可:
n 使用数据集的字段编辑器加入计算字段或是其他类型的临时字段。
n 在OnCalcFields事件处理函数中使用程序代码执行计算字段的工作。
现在就让我们使用一个简单的范例,说明如何使用简易的计算字段来帮助应用程序进行临时的运算工作。在这个范例中我们希望能够了解为员工加薪之后每一位员工的薪水,以决定加薪的幅度。由于这个应用只是提供决策者临时的需求,而不需要把每一个加薪计算的结果储存在数据表中,因此,计算字段在这个应用中是非常适合使用的。我们将在数据集中建立一个临时浮点类型的计算字段用来储存每一次的计算结果。
首先启动目标数据集控件的字段编辑器以准备新增计算字段(见图3-15)。

图3-15 启动TClientDataSet的字段编辑器
接着点击鼠标右键启动快捷菜单,从其中选择New field…项目以启动New Field对话框定义要建立的字段对象种类(见图3-16)。

图3-16 在字段编辑器中启动快捷菜单,选择New field…以建立临时字段
此时Delphi会显示如图3-17所示的对话框,让程序员定义各种不同的临时字段对象,定义字段的种类以及字段名称等特性。例如在下面的对话框中定义了一个类型为浮点数,名称为AdjustedSalary的计算字段。

图3-17 在New Field对话框中建立计算字段,设定其名称和字段类型
每一个数据集允许建立的临时字段并不相同,表3-4是Delphi允许建立的临时字段类型,但是有一些临时字段只能在特定的数据集中使用。例如TSimpleDataSet便没有提供InternalCalc和Aggregate类型的临时字段,但是TClientDataSet则提供了所有类型的临时字段。
表3-4
|
字段类型 |
目的 |
|
Data |
取代现有数据表中的字段 |
|
Calculated |
计算字段,在OnCalcFields事件处理函数中动态计算字段数值 |
|
Lookup |
是用来查询信息使用的查询字段 |
|
InternalCalc |
客户端数据集使用的内部计算字段,是用来临时储存数据使用的字段,不像Calculated字段,InternalCalc并不在OnCalcFields事件处理函数中计算 |
|
Aggregate |
Aggregate类型的字段 |
在图3-17中定义了AdjustedSalary计算字段之后,我们便可以在包含这个计算字段的数据集控件的OnCalcFields事件处理函数中撰写如下的程序代码,在应用程序执行时动态地计算此计算字段的结果,也就是根据不同的加薪幅度来计算每一位员工的薪资信息:
procedure TdmDBExpress.cdsTestCalcFields(DataSet: TDataSet);
begin
try
DataSet.FieldByName('AdjustedSalary').Value :=
DataSet.FieldByName('Salary').Value *
(1 + StrToFloat(frmPerfMain.ledtAdjustedPercent.Text) / 100.0);
except
on Exception do;
end;
end;
procedure TfrmPerfMain.bbtnAdjustClick(Sender: TObject);
begin
dmDBExpress.cdsTest.Edit;
dmDBExpress.cdsTest.Cancel;
end;
上面的程序代码先取出储存员工薪资真正字段的数值,再乘以用户在应用程序中输入的加薪百分比,并且把计算的结果储存在计算字段AdjustedSalary中。请读者注意,当使用数据集加入了计算字段之后,程序员便可以使用像真正数据表中的字段的方式来存取和使用计算字段。
图3-18便是范例程序使用计算字段的画面,从中读者可以发现计算字段对于数据感知控件来说就像是真正的数据表字段一样,可以显示、修改或是进行任何的更改。程序员当然也可以根据用户对于计算字段的更改,再使用程序代码来决定如何进行额外的处理。

图3-18 计算字段执行的状态

续图3-18
虽然计算字段在使用上很方便,又很具弹性,但是数据集在许多的情形下都会触发OnCalcFields事件处理函数,这造成了应用程序大量的计算负荷,因此,读者必须注意不要在OnCalcFields事件处理函数中执行太过复杂的计算,以避免应用程序的执行效率被计算字段拖垮。






