深入數據集裡的數據
數據的狀態
用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數據集組件的當前狀態:
[delphi]
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;
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
遍歷記錄集以及概括某些值時,我們需要用到數據集組件中的方法。看看以下代碼:
[delphi]
...
ADOTable1.DisableControls;
try
ADOTable1.First; //將當前行指向到數據集的第一條記錄
while not ADOTable1.EOF do //EOF(BOF)屬性指出這是否是數據集的最後(第一行)記錄。
begin;
Do_Summing_Calculation; //求和等表達式語句
ADOTable1.Next; //將當前行移動至數據集的下一條記錄
end;
finally
ADOTable1.EnableControls;
end;
...
...
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屬性用來存儲和設置當前記錄的位置。用法如下:
[delphi]
var Bok : TBookmarkStr
...
Bok :=ADOTable1.Bookmark;
{iterationcode}
ADOTable1.Bookmark:= Bok;
var Bok : TBookmarkStr
...
Bok :=ADOTable1.Bookmark;
{iterationcode}
ADOTable1.Bookmark:= Bok;
Thevalue of data
前面代碼中的Do_Summing_Calculation部分,多用來獲取數據集中某些字段(列)的值,並進行求和等操作。
當我們在談論數據集中的記錄值時,也就是在談論數據字段的值。正如前面章節中看到的,用來表示數據集字段的不可見字段組件——在示例中,我們用Object Inspector來設置一個數據集的持久性字段列表。
數據感知控件連接到一個數據集後,用戶通過示例中的那些操作來遍歷數據集。當我們想直接在代碼中使用這些值時,我們需要知道如何讀取它們。
默認情況下,Delphi用以下方式命名字段對象:表名+字段名。也就是說,如果連接到的表中有Type字段,那麼該字段對象的名稱是:ADOTable1Type。
要訪問字段的數據值,可用以下方式。
[delphi]
ADOTable1Type.Value
ADOTable1.Fields[x].Value
ADOTable1.FieldByName('Type').Value
ADOTable1Type.Value
ADOTable1.Fields[x].Value
ADOTable1.FieldByName('Type').Value注:數據集的所有字段都存放在字段數組中。 x表示字段在字段數組中的位置。
Value屬性持有該字段對象的數據值。由於值是varian 類型的,因此需要強制轉換為我們目前需要的類型。換言之,應用程序應使用AsString屬性將字段中的值(日期、整數、貨幣...)轉換為一個字符串——當我們需要字符串形式的字段值時。
現在,我們可以寫出整個代碼了,用來遍歷記錄集並計算表中有多少個“database”應用。(當然,是用的我們AboutDelphi.mdb數據庫中的Applications表)。
[delphi]
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));
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!
這就是第五章內容。下次,我們將看到如何添加,刪除和插入記錄集到數據庫表中。