亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

多層數據庫開發六:什么是數據集

2019-11-18 18:11:18
字體:
來源:轉載
供稿:網友
第六章 什么是數據集
  Delphi 4中有四種類型的標準數據集構件,分別是TTable、TQuery、TStoredPRoc和TClientDataSet。這些數據集構件都是從一個共同的基類TDataSet繼承下來的,其中,只有TClientDataSet是直接從TDataSet繼承下來的,而TTable、TQuery、TStoredProc的直接上級是TDBDataSet,TDBDataSet的上級是TBDEDataSet,TBDEDataSet 的上級才是TDataSet。這幾個類之間的繼承關系可以用圖6.1來表示。
  圖6.1 數據集的繼承關系
  TDataSet是所有數據集的抽象基類,它的大部分屬性和方法是虛擬的或抽象的。所謂虛擬的方法,是指這些方法可以被派生類重載。所謂抽象的方法,是指這些方法只有聲明,沒有定義,派生類必須給出定義后才能調用這些方法,不同的派生類可以有不同的定義。
  由于TDataSet中包含抽象的方法,您不能直接創建它的實例,否則會引起運行期錯誤。
  如果從功能上劃分,TDataSet的屬性和方法可以分為這么幾大塊:打開和關閉數據集、瀏覽記錄、編輯數據、書簽管理、控制連接、訪問字段、記錄緩沖區管理、過濾、事件。
6.1 打開和關閉數據集
  在對數據集進行任何操作之前,首先要打開數據集。要打開數據集,可以把Active屬性設為True,例如:
  CustTable.Active := True;
  也可以調用Open函數,例如:CustQuery.Open;
  要關閉數據集,可以把Active屬性設為False或者調用Close函數。
6.2 數據集的狀態
  數據集的狀態(State屬性)決定了當前能夠對數據集進行的操作,例如,當數據集已經關閉,它的狀態是dsInactive,此時就不能訪問數據集的任何數據。
6.2.1 State屬性
  State屬性是只讀的,下面列出了State屬性可能的值:
.dsInactive 數據集已關閉,不能訪問它的數據;
.dsBrowse 數據集已打開,可以瀏覽數據但不能修改數據;
.dsEdit 此時為編輯狀態,可以修改數據;
.dsInsert 此時可以插入一條新的記錄;
.dsSetKey 只適用于TTable和TClientDataSet,此時可以設置范圍和鍵值,并且可以調用GotoKey函數;
.dsCalcFields 正在處理OnCalcFields事件,此時不能修改非計算字段的值;
.dsCurValue 內部使用;
.dsNewValue 內部使用;
.dsOldValue 內部使用;
.dsFilter 正在進行過濾操作。
  當一個數據集剛剛打開的時候,它的State屬性被設為dsBrowse,以后,State屬性的值會隨著應用程序的操作自動變化。
  要使數據集進入dsBrowse、dsEdit、dsInsert或dsSetKey狀態,就得調用相應的方法。
   例如,要使數據集CustTable進入dsInsert狀態,程序示例如下:
Procedure TForm1.InsertButtonClick(Sender: TObject);
Begin
CustTable.Insert;{進入dsInsert狀態}
AddressPromptDialog.ShowModal;
If AddressPromptDialog.ModalResult := mrOK then
CustTable.Post; {恢復為dsBrowse狀態}
Else
CustTable.Cancel; {恢復為dsBrowse狀態}
End;
  從上面這個例子可以看出,有些操作會使數據集自動變成dsBrowse狀態,例如,調用Post函數如果成功的話,數據集就恢復為dsBrowse狀態,如果調用Post沒有成功,數據集仍然保持原來的狀態。調用Cancel也能使數據集恢復為dsBrowse狀態。
  如果把Active屬性設為False,或者調用Close,將使數據集進入dsInactive狀態。例如,下面兩行代碼是等價的:
  CustTable.Active := False;
  CustTable.Close;
  有些狀態如dsCalcFields、dsCurValue、dsNewValue、dsOldValue和dsFilter不能被應用程序所控制,而是由數據集本身根據需要自動設置的。例如,當正在處理OnCalcFields事件時,就自動進入dsCalcFields狀態。當退出處理OnCalcFields事件的句柄時,數據集自動恢復成原先的狀態。
  當數據集的狀態發生改變時,會觸發TDataSource構件的OnStateChange事件,如果這個TDataSource構件的DataSet屬性指定了這個數據集的話。
  下面詳細介紹數據集的各種狀態以及怎樣進入這些狀態。
6.2.2 dsInactive狀態
  當數據集已關閉時,就處于dsInactive狀態。此時,不能訪問它的任何數據。
  要使數據集進入dsInactive狀態,可以把Active屬性設為False,或者調用Close。在數據集將要關閉之前,會觸發BeforeClose事件。當數據集剛剛關閉,會觸發AfterClose事件。如果在數據集處于dsEdit或dsInsert狀態時調用Close,應當在處理BeforeClose事件的句柄中提示用戶是認可還是取消。程序示例如下:
Procedure CustTable.VerifyBeforeClose(DataSet: TDataSet)
Begin
If (CustTable.State = dsEdit) or (CustTable.State = dsInsert) then
Begin
If MessageDlg('認可修改嗎?', mtConfirmation, mbYesNo, 0) = mrYes then
CustTable.Post;
ElseCustTable.Cancel;
End;
End;
6.2.3 dsBrowse狀態
  當一個數據集剛剛打開的時候,數據集總是處于dsBrowse狀態,此時,可以顯示數據集中的記錄,但不能編輯和插入記錄。
  dsBrowse狀態可以認為是數據集的基本狀態,在此狀態下,可以進入其他狀態。例如,調用Insert或Append函數將使數據集的狀態從dsBrowse變成dsInsert(當然,這還取決于其他因素,如CanModify屬性的值),調用SetKey將使數據集從dsBrowse變成dsSetKey狀態。
  TDataSet有兩個方法可以使數據集回到dsBrowse狀態,一個是Cancel,它將取消當前正在進行的編輯、插入、搜索等操作,使數據集回到dsBrowse狀態。另一個是Post,它將試圖把修改了的數據保存到數據集中,如果成功的話,數據集將回到dsBrowse狀態,如果沒有成功,數據集仍然保持原先的狀態。
6.2.4 dsEdit狀態
  如果應用程序要修改數據集的數據,必須首先進入dsEdit狀態。要進入dsEdit狀態,可以調用Edit。不過,調用Edit并不能保證一定能進入dsEdit狀態,這還取決于CanModify屬性的值。如果這個屬性返回True的話,表示數據集是可以讀和寫的。
  對于TTable構件來說,如果ReadOnly屬性設為True,CanModify屬性肯定返回False。對于TQuery構件來說,如果RequestLive屬性設為False,CanModify屬性肯定返回False。
  即使數據集進入了dsEdit狀態,也并不意味著用戶就一定能修改數據,數據控件的ReadOnly屬性還必須設為False。此外,對于SQL數據庫來說,用戶能不能修改數據還取決于用戶有沒有修改數據的權限。
  要從dsEdit狀態返回到dsBrowse狀態,可以調用Cancel、Post或Delete函數,其中,如果Post和Delete沒有調用成功的話,就仍然保持dsEdit狀態。
  在數據控件中,當用戶修改了數據后把輸入焦點移走,就相當于調用Post函數,將使數據集回到dsBrowse狀態。
6.2.5 dsInsert狀態
  如果應用程序要插入新的記錄,必須首先進入dsInsert狀態。要進入dsInsert狀態,可以調用Insert或Append函數。不過,調用Insert或Append并不能保證一定能進入dsInsert狀態,這還取決于CanModify屬性的值是否返回True。
  即使數據集進入了dsInsert狀態,也并不意味著用戶就一定能插入記錄,數據控件的ReadOnly屬性還必須設為False。此外,對于SQL數據庫來說,用戶能不能插入記錄還取決于用戶有沒有修改數據的權限。
  要從dsInsert狀態返回到dsBrowse狀態,可以調用Cancel、Post或Delete函數,其中,如果Post沒有調用成功的話,就仍然保持dsInsert狀態。
  在數據控件中,當用戶修改了數據后把輸入焦點移走,就相當于調用Post,將使數據集回到dsBrowse狀態。
6.2.6 dsSetKey狀態
  可以調用Locate、Lookup在數據集中搜索特定的記錄。對于TTable構件來說,還可以調用GotoKey、GotoNearest、FindKey或FindNearest在表格中搜索特定的記錄。在調用上述方法之前,必須首先使數據集進入dsSetKey狀態。要使數據集進入dsSetKey狀態,可以調用SetKey。調用了上述方法后,數據集又回到dsBrowse狀態。
  另外,可以對數據集進行過濾。對于TTable構件來說,還可以預先設置范圍。在進行過濾和范圍操作前,也要首先進入dsSetKey狀態。
6.2.7 dsCalcFields狀態
  當OnCalcFields事件被觸發時,就會使數據集進入dsCalcFields狀態。在處理OnCalcFields事件的句柄中,應當給出“計算字段”的值。
  在dsCalcFields狀態下,除了“計算字段”外,應用程序不能修改其他字段的值,因為如果其他字段的值發生變化,又會導致OnCalcFields事件被觸發,從而導致無限循環。
  當OnCalcFields事件處理完畢,數據集又回到dsBrowse狀態。
6.2.8 dsFilter狀態
  當OnFilterRecord事件被觸發時,就會使數據集進入dsFilter狀態。在此狀態下,不允許修改數據集的記錄,否則,過濾就無法正確執行。
  當OnFilterRecord事件處理完畢,數據集就回到dsBrowse狀態。
6.2.9 dsNewValue、dsOldValue或dsCurValue
  在允許緩存更新的情況下,當用戶修改數據集的記錄時,數據集有可能會進入dsNewValue、dsOldValue或dsCurValue狀態。在這三種狀態下,可以通過字段(TField)的NewValue、OldValue或CurValue屬性來訪問當時的值。
  上述三個狀態是由Delphi 4內部使用的,應用程序無法主動進入上述三種狀態。
6.3 瀏 覽 記 錄
  每個活動的數據集都有一個指針,指向當前記錄。很多對數據集的操作都是針對當前記錄,許多數據控件也只顯示當前記錄的數據,因此,在數據庫應用程序中知道當前記錄的位置是非常重要的。
  數據庫應用程序往往要改變當前記錄的位置,這時候就要用到下面這些方法:
.First 使第一條記錄成為當前記錄;
.Last 使最后一條記錄成為當前記錄;
.Next 使下一條記錄成為當前記錄;
.Prior 使前一條記錄成為當前記錄;
.MoveBy 使距離當前記錄若干行的記錄成為當前記錄。
  此外,Delphi 4中有一個TDBNavigator構件,專門用來瀏覽記錄,它把上述方法用按鈕來實現。
  除了上述方法外,TDataSet中還有兩個只讀的布爾類型的屬性用來判斷當前記錄的位置,一個是Bof,如果這個屬性返回True,表示現在已到了數據集的開始位置。另一個是Eof,如果這個屬性返回True,表示現在已到了數據集的末尾。
6.3.1 First和Last
  調用First函數能夠使數據集的第一條記錄成為當前記錄,并且把Bof屬性設為True。如果第一條記錄已經是當前記錄了,First就什么也不干。程序示例如下:
  CustTable.First;
  調用Last函數能夠使數據集的最后一條記錄成為當前記錄,并且把Eof屬性設為True。如果最后一條記錄已經是當前記錄,Last就什么也不干。程序示例如下:
  CustTable.Last;
  用TDBNavigator構件實現的導航器上有兩個按鈕,分別對應著First和Last。
6.3.2 Next和Prior
  調用Next函數能夠使下一條記錄成為當前記錄。如果當前記錄已經是數據集的最后一條記錄,Next就什么也不干。程序示例如下:
  CustTable.Next;
  調用Prior能夠使前一條記錄成為當前記錄。如果當前記錄已經是數據集的第一條記錄,Prior就什么也不干。程序示例如下:
  CustTable.Prior;
6.3.3 MoveBy
  調用MoveBy函數使數據集中的另一條記錄成為當前記錄,該記錄距原先的當前記錄若干行。MoveBy需要傳遞一個參數,指定相隔的行數,正數表示向記錄編號增大的方向移動,負數表示向記錄編號減小的方向移動。程序示例如下:
  CustTable.MoveBy(-2);
  MoveBy返回實際移動的行數,返回值與傳遞給MoveBy的參數有可能不同。
  注意:在多用戶環境下,其他用戶有可能正在修改、插入或刪除記錄,這樣,一條記錄原來距當前記錄是5行,現在有可能變為4行和6行,甚至該記錄都不存在了,因為其他用戶修改該記錄的數據或刪除了該記錄。
6.3.4 Eof和Bof屬性
  TDataSet有兩個只讀的屬性Eof和Bof,分別用于判斷是否到了數據集的末尾和開頭。在遍歷數據集的所有記錄時經常要用到這兩個屬性。
  如果Eof屬性返回True,表示現在已到了數據集的末尾。
  進行下列操作時會把Eof屬性設為True:
.打開一個空的數據集;
.調用了Last;
.調用了Next,而現在已經在數據集的最后一條記錄;
.調用了SetRange,而范圍是無效的。
  除了上述情況外,Eof屬性都將返回False。
  Eof屬性通常用在一個循環中,每調用一次Next就要判斷一下Eof屬性,以避免對不存在的記錄進行操作。程序示例如下:
CustTable.DisableControls;
Try
CustTable.First;
While not CustTable.EOF Do
Begin
...
CustTable.Next;
End;
Finally
CustTable.EnableControls;
End;
上述代碼同時演示了在遍歷數據集的所有記錄時怎樣暫時禁止數據控件跟著刷新。在遍歷數據集的所有記錄前應當調用DisableControls禁止刷新,這樣能夠加快遍歷的速度,因為刷新也是要花時間的。遍歷結束后,應當調用EnableControls恢復刷新。
  EnableControls最好在Try...Finally結構的Finally部分調用,這樣能保證即使在遍歷時出現異常,也能保證刷新能得到恢復。
  如果Bof屬性返回True,表示現在已到了數據集的開頭。
  進行下列操作時會把Bof屬性設為True:
.打開一個非空的數據集;
.調用了First;
.調用了Prior,而現在已經在數據集的第一條記錄。
  除了上述情況外,Bof屬性都將返回False。與Eof屬性一樣,Bof屬性通常用在一個循環中,每調用一次Prior就要判斷一下Bof屬性,以避免對不存在的記錄進行操作。程序示例如下:
CustTable.DisableControls;
Try
While not CustTable.BOF Do
Begin
...
CustTable.Prior;
End;
Finally
CustTable.EnableControls;
End;
6.4 書 簽
  書簽的作用是在數據集的某個位置做一個標記,以后可以快速方便地回到那個位置。TDataSet中提供了若干個屬性和方法用于管理書簽。
  如果讀Bookmark屬性,返回當前記錄的書簽。如果寫Bookmark屬性,它能使一個指定的書簽成為當前書簽。
  TDataSet中有關書簽的幾個函數都是虛擬的,TDataSet的派生類TBDEDataSet重新定義了這些方法,包括:
.BookmarkValid判斷某個書簽是否合法;
.CompareBookmarks比較兩個書簽是否相同;
.GetBookmark創建一個書簽來標記當前記錄;
.GotoBookmark回到用GetBookmark標記的位置;
.FreeBookmark刪除一個書簽。
  要創建一個書簽,首先要聲明一個TBookmark類型的變量,然后調用GetBookmark函數創建一個標記當前記錄的書簽。TBookmark類型的變量實際上是一個無類型的指針。
  在調用GotoBookmark之前,最好先調用BookmarkValid判斷書簽是否合法,因為書簽標記的記錄有可能已刪掉。如果BookmarkValid返回True,說明書簽是合法的,可以調用GotoBookmark跳轉到書簽標記的位置。
可以調用CompareBookmarks比較兩個書簽是否相同,如果兩個書簽不同,這個函數就返回1。如果兩個書簽相同或者都是NIL,這個函數就返回0。
  GotoBookmark需要傳遞一個參數,即書簽。
  FreeBookmark用于刪除一個書簽。當一個書簽已用不到時,應當及時刪除它,因為書簽也是一種資源。
  下面這段代碼演示了書簽的用法:
Procedure DoSomething (const Tbl: TTable)varBookmark: TBookmark;
Begin
Bookmark := Tbl.GetBookmark;
Tbl.DisableControls;
Try
Tbl.First;
While not Tbl.EOF Do
Begin
...
Tbl.Next;
End;
Finally
Tbl.GotoBookmark(Bookmark);
Tbl.EnableControls;
Tbl.FreeBookmark(Bookmark);
End;
End;
6.5 搜索特定的記錄
  可以調用Locate和Lookup函數在數據集中搜索特定的記錄。
   Locate用于在數據集中定位一條特定的記錄,并使該記錄成為當前記錄。Locate需要傳遞三個參數,第一個是KeyFields參數,用于指定要按哪些字段搜索,第二個是KeyValues參數,用于指定每個字段相應的值,第三個是Options參數,用于設置搜索選項。
  下面這個例子搜索Company字段的值為“Professional Ltd.”的記錄:
var
LocateSuccess: Boolean;
SearchOptions: TLocateOptions;
Begin
SearchOptions := [loPartialKey];
LocateSuccess := CustTable.Locate('Company', 'Professional Ltd.',SearchOptions);
End;
  如果Locate找到了一條符合條件的記錄,就把該記錄變為當前記錄,并返回True。如果Locate沒有找到匹配的記錄,就返回False。
  對于Locate來說,KeyFields參數指定的字段越多,搜索的條件就越精確。如果KeyFields參數需要指定多個字段,彼此之間要用分號分開。由于字段的數據類型可能各不相同,因此,KeyValues是一個Variant類型的參數。如果KeyFields參數指定了多個字段,KeyValues參數必須是一個可變類型的數組。程序示例如下:
  With CustTable Do
   Locate('Company;Contact;Phone', VarArrayOf(['Sight Diver','P']), loPartialKey);
   Lookup與Locate非常相似,也是在數據集中搜索特定的記錄。不同的是,如果找到匹配的記錄,Lookup能返回該記錄中若干個字段的值。
   Lookup需要傳遞三個參數,第一個是KeyFields參數,用于指定要按哪些字段搜索,第二個是KeyValues參數,用于指定每個字段相應的值,第三個是ResultFields參數,用于指定要返回哪些字段的值。
  下面這個例子在CustTable中搜索Company字段的值為“Professional Ltd.”的記錄,并返回Company、Contact、Phone等字段的值:
var
LookupResults: Variant;
Begin
With CustTable Do
LookupResults := Lookup('Company', 'Professional Divers, Ltd.', 'Company;Contact; Phone');
End;
  如果ResultFields參數指定了多個字段,Lookup返回一個可變類型的數組。如果沒有找到匹配的記錄,Lookup將返回一個空的數組。程序示例如下:
var
LookupResults: Variant;
Begin
With CustTable Do
LookupResults := Lookup('Company; City', VarArrayOf(['Sight Diver',
  'Christiansted']), 'Company; Addr1; Addr2; State; ZEnd;
6.6 過 濾
  一個應用程序往往只對數據集的部分記錄感興趣,例如,可能只對一個客戶表中來自廣東的客戶感興趣。這種情況下,可以用過濾技術把符合特定條件的記錄過濾出來。
  不過,對于一個字段很多的數據集來說,最好還是使用查詢。
6.6.1 允許過濾
  要對數據集進行過濾,首先要指定過濾條件,并設置FilterOptions屬性設置有關選項(可選),然后把Filtered屬性設為True。以后如果不想進行過濾,只要把Filtered屬性設為False。
  要指定過濾條件有兩種方式:一是設置Filter屬性,二是在處理OnFilterRecord事件的句柄中給出過濾條件。
  Filter屬性適合于在運行期使用,它能夠動態地指定過濾條件,能夠根據需要改變過濾條件。不過,Filter屬性是一個字符串,過濾條件相對比較簡單。雖然可以用運算符構成復合的條件表達式,但只限于幾個常見的運算符。更主要的是,用Filter屬性指定的表達式中只能出現數據集中已有的字段名和常量,不能出現其他數據。
  而OnFilterRecord事件則靈活得多,它能夠在設計期就指定好過濾條件。而在處理OnFilterRecord事件的句柄中,可以任意指定過濾條件,過濾條件可以很復雜。
6.6.2 Filter屬性
  Filter屬性是一個字符串,可以這樣設置Filter屬性:
  Dataset1.Filter := '''State'' = ''CA''';
  也可以這樣設置Filter屬性:
  Dataset1.Filter := Edit1.Text;
  上面這行代碼允許讓用戶自己輸入過濾條件。甚至還可以把上述兩行代碼結合起來:
  Dataset1.Filter := '''State'' = ' + Edit1.Text;
  設置了過濾條件后,只要把Filtered屬性設為True,過濾即有效。
  可以用比較和邏輯運算符構造復合的過濾條件,這些運算符包括:
. <小于;
. >大于;
. >=大于等于;
. <=小于等于;
.=等于;
. <>不等于;
.AND兩邊的表達式都必須為True;
.NOT表達式不能為True;
.OR兩個表達式只要有一個為True。
  下面這個例子用AND運算符限制CustNo字段必須大于1400且小于1500:
  (CustNo > 1400) AND (CustNo < 1500);
  注意:在Filtered屬性設為True的情況下,用戶修改、插入的記錄有可能不符合過濾的條件,這時候,會拒絕接受與過濾條件矛盾的記錄。
6.6.3 OnFilterRecord事件
  在Filtered屬性設為True的情況下,數據集中的每條記錄都會觸發OnFilterRecord事件,這樣,就有機會決定是否要把記錄過濾。
  處理OnFilterRecord事件的句柄中有一個布爾類型的Accept參數,把這個參數設為True表示接受此記錄,把這個參數設為False表示把此記錄過濾掉。程序示例如下:
Procedure TForm1.Table1FilterRecord(DataSet: TDataSet;
var Accept: Boolean);
Begin
Accept := DataSet['State'] = 'CA';
End;
  上面這個例子的意思是,只有State字段的值為CA的記錄才被接受。
  注意:由于數據集的每條記錄都會觸發OnFilterRecord事件,因此,處理OnFilterRecord事件的代碼要盡可能地簡短,尤其是對一個有很多條記錄的大型數據集。
  有時候,程序需要按多種不同的過濾條件進行過濾,可以建立多個處理OnFilterRecord事件的句柄,然后在運行期動態地切換事件句柄,程序示例如下:
  DataSet1.OnFilterRecord := NewYorkFilter;Refresh;
6.6.4 設置過濾選項
  FilterOptions屬性用于設置過濾的選項。這個屬性是一個集合,可以是空集(默認),也可以包含下列元素:
.foCaseInsensitive比較字符串時忽略大小寫;
.foPartialCompare對于字符串類型的字段必須全字匹配,不允許部分匹配。
  例如,為了在比較State字段時忽略大小寫,可以這樣設置:
  FilterOptions := [foCaseInsensitive];
  Filter := '''State'' = ''CA''';
6.6.5 在過濾后的數據集中瀏覽記錄
  過濾后的數據集實際上是原來的數據集的一個子集。TDataSet提供了四個方法用于在過濾后的數據集中瀏覽記錄,它們是:
.FindFirst使過濾后的數據集中的第一條記錄成為當前記錄;
.FindLast使過濾后的數據集中的最后一條記錄成為當前記錄;
.FindNext使過濾后的數據集中的下一條記錄成為當前記錄;
.FindPrior使過濾后的數據集中的前一條記錄成為當前記錄。
  上述四個方法如果調用成功,就返回True,否則,就返回False??梢詸z查一個只讀的Found屬性,看看上次調用是否成功。
  如果通過Filter屬性或OnFilterRecord事件設置了過濾條件,而Filtered屬性設為False,調用上述四個方法時會自動暫時允許過濾,然后移動當前記錄的位置,最后又禁止過濾。換句話說,上述四個方法可以不理會Filtered屬性是怎樣設置的。
  如果沒有設置過濾條件,上述四個方法即相當于First、Last、Next和Prior。
6.7 修 改 數 據
  TDataSet中提供了一些方法用于在數據集中更新、插入和刪除記錄,它們是:
.Edit使數據集進入dsEdit狀態;
.Append在數據集的末尾添加一條記錄;
.Insert在數據集的當前位置插入一條記錄;
.Post試圖把用戶對數據的修改寫到數據集中;
.Cancel取消用戶對數據的修改,使數據集回到dsBrowse狀態;
.Delete刪除當前記錄。
6.7.1 進入dsEdit狀態
  要編輯數據集的記錄,首先要進入dsEdit狀態。要進入dsEdit狀態,調用Edit函數。不過,調用Edit不一定會使數據集進入dsEdit狀態,還取決于CanModify屬性的值。
  一旦數據集進入了dsEdit狀態,用戶就可以在數據控件上修改當前記錄的值。當用戶把輸入焦點從當前記錄上移走,即相當于調用了Post函數。程序示例如下:
With CustTable Do
Begin
Edit;
FieldValues['CustNo'] := 1234;
Post;
End;
  要取消當前未決的修改,用戶可以按ESC鍵或單擊用TDBNavigator構件實現的導航器上的Cancel按鈕。
  在使用緩存更新技術(CachedUpdates屬性設為True)的情況下,調用Post只是把數據寫到緩存中,而不是直接寫到數據集中。要把緩存中的數據寫到數據集中,需調用ApplyUpdates函數。
6.7.2 插入新的記錄
  要在數據集中插入新的記錄,首先要進入dsInsert狀態。要進入dsInsert狀態,可以調用Insert或Append函數。不過,調用Insert或Append不一定會使數據集進入dsInsert狀態,還取決于CanModify屬性的值。
  一旦進入了dsInsert狀態,用戶就可以在數據控件(一般是TDBGrid)中插入一條新的記錄,并給這條記錄輸入數據。
  如果要通過編程來插入新的記錄,就要注意Insert和Append的區別。Insert將把一條新的記錄插入到當前記錄的前面,而Append將把一條新的記錄添加到數據集的末尾。
  插入了新的記錄后,應當調用Post或在CachedUpdates屬性設為True的情況下調用ApplyUpdates把新的記錄寫到數據集中。
  如果數據集是已建立了索引的Paradox或dBASE表,新記錄將自動移到恰當的位置。
  如果數據集沒有建立索引,新記錄就插入到數據集的當前位置(Insert)或末尾(Append)。
6.7.3 刪除記錄
  調用Delete函數將刪除當前記錄,并且使數據集回到dsBrowse狀態。如果窗體上有TDBNavigator構件的話,用戶可以單擊導航器上的“Delete”按鈕刪除當前記錄。當前記錄被刪除后,下一條記錄就成為當前記錄。
  如果刪除的本來就是最后一條記錄,則前一條記錄成為當前記錄。
6.7.4 修改整條記錄
  除了TDBGrid和TDBNavigator外,大部分數據控件只能工作于數據集的一個或幾個字段,而不是整條記錄。
  不過,TDataSet提供了若干個方法可以直接修改整條記錄而不是單獨的字段,這些方法包括:
.AppendRecord類似于Append,但可以給字段賦值,不需要調用Post;
.InsertRecord類似于Insert,但可以給字段賦值,不需要調用Post;
.SetFields對當前記錄的字段賦值,需要顯式地調用Post。
  上述三個方法都要傳遞一個TVarRec類型的數組作為參數,該數組的每一個元素對應著一個字段的值。如果數組的元素個數小于數據集的字段個數,剩下字段的值就是NULL。
  對于沒有建立索引的數據集來說,AppendRecord把一條新的記錄加到數據集的末尾。對于已建立索引的數據集來說,新記錄將自動移到一個恰當的位置。
  SetFields用于對當前記錄的字段賦值。在調用SetFields之前,首先要調用Edit,使數據集進入dsEdit狀態。調用了SetFields后,需要顯式地調用Post函數。
  調用SetFields時,如果您只想對部分字段賦值,讓其他字段的值保持不變,可以用NULL或NIL去賦值。
  假設一個數據集中有五個字段,分別是Name、Capital、Continent、Area和Population,可以這樣對它們賦值:
CountryTable.InsertRecord(['Japan', 'Tokyo', 'Asia']);
  上述程序在數據集中插入了一條新的記錄,并且對前三個字段賦了值。現在可以再次對當前記錄賦值,不過,這次只想對Area字段和Population字段賦值,程序就要這樣寫:
With CountryTable Do
Begin
If Locate('Name', 'Japan', loCaseInsensitive) then
Begin
Edit;
SetFields(NIL, NIL, NIL, 344567, 164700000);
Post;
End;
End;
  注意:此處要用NIL而不是NULL,否則,前三個字段會被設為空。
6.8 事 件
  TDataSet的事件主要分為兩大類,一類是Before系列,另一類是After系列,列表如下:
.BeforeOpen,AfterOpen發生在數據集打開前后;
.BeforeClose,AfterClose發生在數據集關閉前后;
.BeforeInsert,AfterInsert發生在插入了一條新的記錄前后;
.BeforeEdit,AfterEdit 發生在進入dsEdit狀態前后;
.BeforePost,AfterPost 發生在寫數據集的前后;
.BeforeCancel,AfterCancel發生在取消修改的前后;
.BeforeDelete,AfterDelete發生在刪除記錄的前后。
  此外,當數據集中增加了一條新的記錄時就會觸發OnNewRecord事件,當“計算字段”的值需要重算時將觸發OnCalcFields事件。
  Before系列的事件常常用來中止操作。例如,當調用Delete函數試圖刪除當前記錄時,在當前記錄將要刪除前會觸發BeforeDelete事件,可以在處理BeforeDelete事件的句柄中調用Abort或觸發一個異常放棄刪除當前記錄,程序示例如下:
Pocedure TForm1.TableBeforeDelete (Dataset: TDataset)
Begin
If MessageDlg('Delete This Record?', mtConfirmation, mbYesNoCancel, 0) <> mrYes Then Abort;
End;
  After系列的事件往往用來在狀態欄上通知用戶,程序示例如下:
Procedure TForm1.Table1AfterDelete(DataSet: TDataSet);
Begin
StatusBar1.SimpleText := Format('有%d 條記錄',[DataSet.RecordCount]);
End;
  OnCalcFields事件主要用于給出“計算字段”的值。AutoCalcFields屬性的值決定了什么時候會發生OnCalcFields事件。
  如果AutoCalcFields屬性設為True,下列情況下會發生OnCalcFields事件:
.數據集被打開時;
.在數據控件中,輸入焦點從一條記錄移到另一條記錄;
.在數據控件中,輸入焦點從一個字段移到另一個字段;
.當前記錄被修改或從數據庫中檢索了一條記錄。
  不過,即使AutoCalcFields屬性設為False,當數據集中的任意一個非計算字段的值發生變化時都會觸發OnCalcFields事件。
  由于OnCalcFields事件有可能是頻繁發生的,因此,處理OnCalcFields 事件的代碼要盡可能地簡短。在AutoCalcFields屬性設為True的情況下,在處理OnCalcFields事件的句柄中不能修改數據集的數據,因為一旦當前記錄被修改,又要觸發OnCalcFields事件,從而導致無限循環。例如,假設您在處理OnCalcFields事件的句柄中調用了Post,就會觸發OnCalcFields事件,導致再次調用Post,再次觸發OnCalcFields事件……
6.9 TBDEDataSet
  TBDEDataSet是從TDataSet繼承下來的,它提供了通過BDE(BorlandDatabase Engine)訪問數據的能力。這一節主要介紹TBDEDataSet,讀者應當對前面介紹的TDataSet已經有了比較深刻的認識。
  與TDataSet一樣,TBDEDataSet也是虛擬的和抽象的,除非您想建立自定義的數據集,否則,一般不需要直接用到TBDEDataSet。
  TBDEDataSet重載了TDataSet中涉及記錄導航、索引和書簽的方法,增加了一些處理BLOB字段、緩存更新的屬性、方法和事件。
6.9.1 CacheBlobs屬性
  TBDEDataSet的CacheBlobs屬性用于控制BDE是否把BLOB字段的內容放到緩存中。如果這個屬性設為True,當應用程序讀取BLOB字段的值時,BDE將把BLOB字段的內容放在緩存中,這樣,當應用程序下次要讀取這個字段的值時,就不必再從數據庫服務器那兒去檢索,只要直接從內存中取過來就行了,這樣可以提高應用程序的性能。
  不過,如果應用程序需要頻繁地更新BLOB字段的值,這時候反而應當把CacheBlobs屬性設為False,這樣能保證檢索到的BLOB字段的值總是最新的。
6.9.2 緩存更新
  TBDEDataSet提供了緩存更新的技術。所謂緩存更新就是,應用程序從數據庫中檢索數據,在本地緩存中建立一個副本,用戶對數據進行修改后,也只是反映在緩存中,以后可以調用ApplyUpdates一次性地把所有的修改反映到數據集中。
  可以看出,緩存更新技術可以明顯地提高應用程序的性能,而且可以方便地取消修改,只要還沒有調用ApplyUpdates。下面列出了TBDEDataSet中有關緩存更新的屬性、方法和事件:
.CachedUpdates如果這個屬性設為True,緩存更新有效;
.UpdateObject用于指定一個TUpdateSQL構件來更新基于查詢的數據集;
.UpdatePending如果緩存中有未決的記錄,這個屬性就返回True;
.UpdateRecordTypes指定數據集中哪些記錄是可見的;
.UpdateStatus返回當前的更新狀態;
.OnUpdateError如果更新過程中出錯將觸發這個事件;
.OnUpdateRecord每更新一條記錄就會觸發一次這個事件;
.ApplyUpdates把緩存中的數據寫到數據集中;
.CancelUpdates把緩存中未決的修改取消;
.CommitUpdates把緩存清掉;l FetchAll從數據庫檢索所有記錄到緩存中;
.RevertRecord撤消對當前記錄的修改。
6.10 TDBDataSet
  TDBDataSet是從TBDEDataSet繼承下來的,它提供了數據庫和會話期管理的能力。
  TDBDataSet中增加了若干個屬性和方法用于管理數據庫和BDE會話期,包括:
.CheckOpen檢查數據庫是否已打開;
.Database返回一個TDatabase構件;
.DBHandle返回一個BDE句柄,調用BDE的API時要用到這個句柄;
.DBLocale返回當前的國際語言驅動程序;
.DB
session返回一個BDE會話期對象;
.DatabaseName用于指定要訪問的數據庫;
.SessionName用于指定一個BDE會話期對象。
  這里詳細解釋一下DatabaseName屬性和SessionName屬性。如果應用程序要訪問遠程數據庫服務器如Sybase、Oracle或InterBase,應當用TDatabase構件來連接數據庫,此時,應當設置DatabaseName屬性指定要連接的數據庫,可以設為TDatabase構件的名稱。如果沒有顯式地使用TDatabase構件,DatabaseName屬性應當設為BDE 別名。對于Paradox和dBASE表來說,可以設為表的路徑。
  SessionName屬性用于指定一個BDE會話期對象。如果應用程序沒有顯式地使用TSession構件,不必設置這個屬性。如果應用程序顯式地使用了多個TSession構件,應當設置SessionName屬性指定其中一個。
  一般來說,應用程序用不到DBHandle、DBLocale和DBSession等屬性,除非要直接調用BDE的API。這三個屬性都是只讀的。
  TDBDataSet中還有一個只讀的Provider屬性,它能夠返回一個IProvider接口。在多層的Client/Server應用程序中,客戶程序需要通過IProvider接口與應用服務器通訊。

上一篇:多層數據庫開發十一:TClientDataSet

下一篇:多層數據庫開發五:連接數據庫

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人免费大片黄在线播放| 欧美性色视频在线| 日本一区二区不卡| 国外成人在线播放| 992tv在线成人免费观看| 久久艹在线视频| 国产日韩av在线| 国产视频自拍一区| 午夜精品一区二区三区视频免费看| 亚洲aaa激情| 国产精品久久久精品| 欧美日韩国产限制| 欧美精品18videos性欧| 久久久久久国产精品三级玉女聊斋| 亚洲成人免费网站| 成人a免费视频| 亚洲欧美国产另类| 日韩经典第一页| 国内精品小视频在线观看| 国产综合香蕉五月婷在线| 中文字幕日韩欧美| 欧美激情第三页| 欧美丝袜第一区| xxx一区二区| 欧美性猛xxx| 亚洲缚视频在线观看| 4k岛国日韩精品**专区| 中国日韩欧美久久久久久久久| 国产经典一区二区| 不卡av在线播放| 97人人爽人人喊人人模波多| 日韩暖暖在线视频| 精品久久久久久中文字幕| 精品亚洲一区二区三区在线播放| 亚洲大尺度美女在线| 日韩禁在线播放| 欧美大片网站在线观看| 国产精品久久久久aaaa九色| 国产精品91久久久| 丁香五六月婷婷久久激情| 亚洲国产成人av在线| 国产精品亚洲аv天堂网| 国产精品免费视频xxxx| 欧美大秀在线观看| 日韩av第一页| 日日摸夜夜添一区| 日韩欧美成人网| 久久久精品久久| 91免费国产视频| 亚洲天堂男人天堂女人天堂| 欧美日韩精品在线观看| 亚洲va国产va天堂va久久| 精品国产一区二区三区久久| 亚洲欧洲在线看| 91久久国产综合久久91精品网站| 国产精品视频自拍| 亚洲影院色无极综合| 久久久久九九九九| 久久国产视频网站| 欧美成在线视频| 秋霞午夜一区二区| 91日韩在线视频| 国产a级全部精品| 亚洲欧洲在线看| 91精品美女在线| 久久影院资源站| 国产色婷婷国产综合在线理论片a| 欧美成人免费全部观看天天性色| 久久中国妇女中文字幕| 国产欧美精品日韩| 懂色av一区二区三区| 成人免费在线视频网址| 亚洲视频综合网| 亚洲老头老太hd| 91欧美视频网站| 91精品免费视频| 一区二区三区回区在观看免费视频| 亚洲国产成人久久综合| 亚洲国产天堂久久综合网| 亚洲美女免费精品视频在线观看| 日韩av网站电影| 成人黄色在线播放| 97久久精品在线| 日韩中文av在线| 91久久夜色精品国产网站| 日韩有码在线电影| 中文字幕在线成人| 欧美一区视频在线| 精品久久久视频| 成年人精品视频| 裸体女人亚洲精品一区| 日本欧美在线视频| 日韩精品中文字幕在线| 欧美日韩一区免费| 怡红院精品视频| 日韩精品在线观看一区| 欧美老女人xx| 91久久久亚洲精品| 国外日韩电影在线观看| 国产精品久久久久av免费| 91国内产香蕉| 亚洲999一在线观看www| 久久久免费精品视频| 九九热精品在线| 在线亚洲国产精品网| 欧美激情精品久久久久久黑人| 成人免费视频网址| 国产精品午夜国产小视频| 国产裸体写真av一区二区| 亚洲高清福利视频| 91久久精品国产| 国产精品女主播视频| 国产一区二区视频在线观看| 97精品国产97久久久久久| 精品久久在线播放| 日韩欧美高清在线视频| 久久精品99久久香蕉国产色戒| 日韩免费在线免费观看| 成人自拍性视频| 欧美极度另类性三渗透| 午夜精品一区二区三区在线视频| 欧美性感美女h网站在线观看免费| 国产精品久久97| 日韩欧美国产中文字幕| 日本一区二三区好的精华液| www.日韩.com| 久久久久久成人| 日韩中文字幕在线精品| 欧美一级片免费在线| 日韩av在线电影网| 自拍偷拍亚洲欧美| 久久久久久免费精品| 中文字幕欧美国内| 青青久久av北条麻妃海外网| 黑人巨大精品欧美一区二区一视频| 国产成人在线一区| 国产suv精品一区二区三区88区| 美女久久久久久久| 亚洲激情久久久| 精品毛片网大全| 国产美女高潮久久白浆| 国产91九色视频| 亚洲午夜色婷婷在线| 久久综合久久八八| 国产精品视频精品| 久久精品国产清自在天天线| 国产美女精彩久久| 中文字幕综合在线| 国产女人18毛片水18精品| 国产精品av在线| 久久九九亚洲综合| 成人福利在线视频| 懂色av中文一区二区三区天美| 97精品视频在线观看| 国产色综合天天综合网| 久久色免费在线视频| 成人性生交大片免费观看嘿嘿视频| 性欧美激情精品| 日韩美女写真福利在线观看| 日韩视频免费大全中文字幕| 另类美女黄大片| 欧美大尺度激情区在线播放| 国产精品色视频| 欧美大胆在线视频|