深入数据集里的数据
数据的状态
用Delphi和ADO开发数据库应用程序时,大部分工作需要数据集(dataset )组件的协助。为了创建一个基于ADO的程序,Delphi提供了一些数据集组件:TAdoTable、TAdoQuery等等用于检索、显示和修改数据库内的表或查询到的数据。
在本教程的第五章,我们将了解怎样来显示、浏览和读取数据——通过数据集组件一些有趣的属性、事件和方法来实现。
挑选、设置、连接和获得(Pick, set, connect and get)
鉴于这是第五章,你应该熟悉了创建一个数据浏览窗体所需要的步骤。在第四章,我们一步步建立了个简单的数据浏览窗体。本章将继续用它来讨论。
目前为止,我们仅用过一个(ADO)数据集组件——TAdoTable。下面,有必要了解一下TADOQuery和TADODataSet(数据集组件)共同的方法和事件。
芝麻开门;芝麻关门(Open Sesame ; Close Sesame)
Delphi数据库开发的出色功能之一就是:可以在程序设计时对数据进行处理。你可以回忆一下——在上一章,我们使用Active属性便在设计时建立了数据的活动连接。
不难理解,在开始处理表的数据之前,程序必须先打开数据集。Delphi有两种方法实现此功能。一是在设计或运行时将Active属性设置为True;二是运行时调用Open方法。例如,添加以下代码到窗体的OnCreate事件句柄中,获得来自ADOTable1组件的数据:
ADOTable1.Open;
注:每个ADO数据集都可通过它自身的ConnectionString属性,或一个ADOConnection组件(及其ConnectionString)访问数据库中的数据。如果ADOTable1组件与ADOConnection1组件相连(推荐使用此方式),打开ADOTable将激活相应的ADOConnection组件。ADOConnection提供两个将被执行的事件:OnWillConnect和OnConnectComplete。
Open方法设置Active属性为True并激活连接。当用完连接后,我们可以设置Active属性为False或调用Close方法断开连接。通常放在窗体的OnClose事件句柄中:
ADOTable1.Close;
在继续之前,需知道对数据集方法和属性的处理,依赖于对数据当前状态的了解。简而言之,数据集的State(状态)属性决定任何时候数据集上的什么行为可以发生或不发生。
如何做(How are you doing?)
如果数据集是关闭的,数据的State将显示为Inactive(非活动)连接。连接关闭时,任何操作、行为或方法都无法作用于数据。首次打开连接时,数据集处于默认的Browse(浏览)状态。你应该始终了解“你的”数据所在的状态。例如,当我们把数据集连接到DBGrid时,用户能够看到底层的数据集(或记录),但要改变某些数据时,必须把State设置为Edit。
认识到程序处理数据时,数据集状态都在不停改变是非常重要的。例如,当浏览DBGrid中数据时(为Browse状态),用户编辑记录时,自动改变状态为Edit。当然,在数据感知控件(DBGrid、DBEdit)AutoEdit属性设为True时,这是默认行为。
但是,但是,我们该如何获得状态呢? ADOTable(或任何其他数据集组件)没有处理状态改变的触发器。
好,让我们看一看:对每个数据集组件,我们通常用一个数据源组件来呈现于一个或多个数据感知控件的连接。就是这样。
每个数据源组件都有一个OnStateChange事件,在底层数据集改变时触发。把下面的代码放到OnStateChange事件句柄中,用窗体的标题来显示ADOTable1数据集组件的当前状态:
procedure TForm1.DataSource1StateChange
(Sender: TObject);
var ds: string;
begin
case ADOTable1.State of
dsInactive : ds := 'Closed';
dsBrowse : ds := 'Browsing';
dsEdit : ds := 'Editing';
dsInsert : ds := 'New record inserting';
else
ds := 'Other states'
end;
Caption := 'ADOTable1 state: ' + ds;
end;
From BOF to EOF and back in the Middle
在上一章,我们用DBNavigator组件来浏览数据集。作为一个可视化的数据集浏览控件,用户可在运行时单击其按钮,来遍历数据集里的记录。
Movingon from BOF to EOF
遍历记录集以及概括某些值时,我们需要用到数据集组件中的方法。看看以下代码:
...
ADOTable1.DisableControls;
try
ADOTable1.First; //将当前行指向到数据集的第一条记录
while not ADOTable1.EOF do //EOF(BOF)属性指出这是否是数据集的最后(第一行)记录。
begin;
Do_Summing_Calculation; //求和等表达式语句
ADOTable1.Next; //将当前行移动至数据集的下一条记录
end;
finally
ADOTable1.EnableControls;
end;
...
多数情况下,数据集连接到一个或多个数据感知控件。长遍历时,发生数据感知控件从数据集“断开”,会是相当有趣的——为防止数据感知控件随活动记录的每次变化而更新。用DisableControls和EnableControls禁用和启用与数据集关联控件的数据显示。
异常捕捉(try-finally)程序块——确保异常发生时,所有的数据感知控件依然连接到数据集。
Bookmarking
调用上述代码前,*指针*很可能在数据集某些*中间*位置——比如用户正在用DBGrid浏览一个数据集。代码使*指针*从*中间*当前行移到结束(EOF)行,导致程序失去原来的位置。如果我们可以存储当前位置并在遍历完成后回到此位置(再次),这会让用户感到非常友好。当然,Delphi具有此功能。 ADOTable(及其他继承至TDataSet的控件)拥有Bookmark属性用来存储和设置当前记录的位置。用法如下:
var Bok : TBookmarkStr
...
Bok :=ADOTable1.Bookmark;
{iterationcode}
ADOTable1.Bookmark:= Bok;
前面代码中的Do_Summing_Calculation部分,多用来获取数据集中某些字段(列)的值,并进行求和等操作。
当我们在谈论数据集中的记录值时,也就是在谈论数据字段的值。正如前面章节中看到的,用来表示数据集字段的不可见字段组件——在示例中,我们用Object Inspector来设置一个数据集的持久性字段列表。
数据感知控件连接到一个数据集后,用户通过示例中的那些操作来遍历数据集。当我们想直接在代码中使用这些值时,我们需要知道如何读取它们。
默认情况下,Delphi用以下方式命名字段对象:表名+字段名。也就是说,如果连接到的表中有Type字段,那么该字段对象的名称是:ADOTable1Type。
要访问字段的数据值,可用以下方式。
ADOTable1Type.Value
ADOTable1.Fields[x].Value
ADOTable1.FieldByName('Type').Value
注:数据集的所有字段都存放在字段数组中。 x
表示字段在字段数组中的位置。
Value属性持有该字段对象的数据值。由于值是varian 类型的,因此需要强制转换为我们目前需要的类型。换言之,应用程序应使用AsString属性将字段中的值(日期、整数、货币...)转换为一个字符串——当我们需要字符串形式的字段值时。
现在,我们可以写出整个代码了,用来遍历记录集并计算表中有多少个“database”应用。(当然,是用的我们AboutDelphi.mdb数据库中的Applications表)。
var
Bok : TBookmarkStr;
ict : Integer;
begin
ict:=0;
Bok:=ADOTable1.Bookmark;
try
ADOTable1.DisableControls;
try
ADOTable1.First;
while not ADOTable1.EOF do
begin
if ADOTable1.FieldByName('Type').AsString = 'database' then Inc(ict);
//if ADOTable1Type.AsString = 'database' then Inc(ict); //其他两种方式
//if ADOTable1.Fields[3].AsString = 'database' then Inc(ict); //双击ADOTable1查看,从上之下从0开始计数
ADOTable1.Next;
end;
finally
ADOTable1.EnableControls;
end;
finally
ADOTable1.Bookmark:=Bok;
end;
ShowMessage('Number of database apps: ' + IntToStr(ict));
我同意!我们应为上述目的而使用ADOQuery!
这就是第五章内容。下次,我们将看到如何添加,删除和插入记录集到数据库表中。