程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 有關TDataSet的研究

有關TDataSet的研究

編輯:Delphi
VCL 的數據庫框架中有一個很重要的抽象類叫TDataSet ,它可以處理非BDE 的數據源。   鑒於Delphi的很多數據庫感知控件都是以TDataSet作為接口和數據庫連接的,為了重復使用Delphi現有的資源,已經使我們的小型數據庫能更加健壯,更加可移植,已經提出公共接口,針對接口編程,因此決定將原來的GPF控件改寫由TDataSet繼承。   TDataSet本身自己已經封裝了記錄緩沖系統。Buffers就是記錄它的記錄緩沖區的。BufferCount記錄可是用緩沖區的個數。但是Buffers的個數比BufferCount多一個。這多出來的一個是TDataSet用來作為臨時緩沖區的,即TempBuffer。雖然TDataSet已經封裝了,但是對緩沖區的所有實現還得在派生類裡實現。但所有在外面可以實現的都是對單個記錄緩沖區的。如:為記錄緩沖區申請空間,釋放空間,初始化緩沖區,以及一些和緩沖區有關的操作。這些在《Delphi 5 開發人員指南》中30章第四節“擴展TDataSet中已經有了很好的說明。

記錄緩沖列表 臨時緩沖區   

0 1 2 3 . . . 最後 臨時                       圖1:記錄緩沖列表結構   由於TDataSet是個抽象類,所以必須在派生類中實現所有的抽象方法。實現這些抽象方法也正是實現我們的GPF(現改名為GDB)。因為正是這些抽象方法實現了DataSet和數據庫數據的連接。最基本的就是InternalOpen和InternalClose兩個方法。另外要實現使用Field,就得實現GetFieldData,SetFieldData。這裡有一點要說明的是在Fields中的Field的順序(即用FIElds[I]訪問的順序)和數據庫中字段的循序是不一樣的。我在這裡就曾經犯過錯誤。我的解決方法是使用Field中的屬性FieldNo,這個屬性可以記錄這個字段的物理位置。然後使用FieldByNumber來訪問字段。(是不是有點麻煩?我也是沒有辦法的辦法)。當然了,你也可以用一個列表按原始順序記錄FIElds的。   TDataSet裡的記錄號即RecNo這個屬性是用來表示當前可以訪問的所以記錄中按當前訪問順序的第RecNo個記錄。感知控件的顯示也依賴於這個屬性。它不是用來表示記錄的物理順序的。因此,在實現的時候,內部管理記錄時要另外使用一個成員變量來表示,相當於一個內部游標。   另外有幾個在《開發指南》中沒有提到的方法我想說明一下,這幾個都與感知控件的顯示有關,因此都在Public下的。   IsSquenced這個在TDataSet中Public下的函數,應該繼承一下。該方法是用來表示記錄的組織是否是連續緊湊的。這個特性在數據庫感知控件中會使用到。比如DBGrid中的垂直滾動條的狀態就是根據這個來決定的。如果該函數返回真,就是說記錄是緊湊的,則滾動條會根據RecNo來決定具體位置。反之,如果是假,則滾動條只有三個狀態,即最上、中間、最下。   CompareBookmark這個函數,使用來判斷兩個記錄的大小的。同樣,這個函數也與感知控件有關。在DBGrid選擇了MultiSelect後,當選擇了一條記錄後,Grid會根據該函數的返回值來決定是否選中鄰近的記錄。其實一句話,就是說Grid在這種狀態下,會選擇所有的相同記錄。   另外有一個函數,GetCanModify是實現特性CanModify的。覆蓋一下可以用來控制DataSet的ReadOnly。   對在第三段我說的TempBuffer我想在補充幾句。TempBuffer這個緩沖區具有很大的作用的,因為它擁有與其他緩沖區相同的特性與操作,而且它對你來說是“生存期自管理”的。這一點在你實現查詢操作時會發現很有用。你應該已經有了比較兩條記錄的函數,但是在查詢時,你只有一條記錄以及查詢條件可以使用。這是你可以將你的查詢條件轉換成記錄,而這條記錄就可以放到TempBuffer中。這樣你的實現就會變得很統一,因為你做的只是兩條記錄的比較。   TDataSet另外封裝了一點就是書簽功能(Bookmark)。一般情況下,Bookmark只要有兩個成員變量就行了。一個是Data(TBookmark類型),一個是Flag(TBookmarkFlag)。 Data使用來記錄你可以借此而訪問到該記錄的值。這是個Pointer類型的變量。因此,你可以把它作為整數使用(如存放記錄號,我就是這樣用的),也可以指向一個記錄的指針,甚至於一個記錄。而Flag是用來記錄當前標簽的位置。在Delphi中TbookmarkFlag是這樣定義的:TBookmarkFlag = (bfCurrent, bfBOF, bfEOF, bfInserted);其中bfCurrent是表示當前位置,即有效Data。BfBOF和bfEOF表示首尾位置。BfInserted表示剛剛插入還沒有提交(Post)的記錄。         理解了Bookmark所需要的成員變量以及其意義。我們看一下在TDataSet中Delphi是如何使用Bookmark的。為了便於說明,我先介紹一下我在實現GDB時使用的Bookmark。     下面是結構:     PGDBBookmarkInfo = ^TGDBBookmarkInfo;     TGDBBookmarkInfo = record        BookmarkData: Integer;        BookmarkFlag: TbookmarkFlag;     End;        首先要解決的是Bookmark放在什麼地方。這其實對外也是看不見的。上面講到記錄緩沖區,其實Bookmark就是接在記錄緩沖區後的。或者更簡單的說,整個緩沖區是由記錄和Bookmark(TGDBBookmarkInfo結構)組成的。         記錄緩沖 書簽(TGDBBookmarkInfo)                圖2: 記錄緩沖區結構         對緩沖區的操作是在TDataSet的派生類裡實現的。有幾個抽象方法SetBookmarkFlag,SetBookmarkData,GetBookmarkData,GetBookmarkFlag。這幾個方法是直接對緩沖區操作的。         TDataSet就是利用這些方法對Bookmark進行操作的。不過,一般設置Bookmark都是在繼承類裡實現的。實現的位置其實是可以想象的到的。由於Bookmark和記錄緩沖區在一起,那麼在對記錄緩沖區操作的時候(讀記錄到緩沖區的時候),也就是GetRecord函數中,你可以將與該記錄關聯的Bookmark寫入。正如上面討論到的,你必須在BookmarkData中填入相應的值。如我這裡,就可以填入記錄號。以後可以用記錄號來訪問該記錄。     InternalGotoBookmark就是利用BookmarkData來定位到記錄的。InternalSetToRecord也是類似的操作。   另外一個由數據感知控件頻繁使用的就是CompareBookmarks。它的兩個參數就TBookmark類型的。你就是根據這個指針來訪問你存放的數據。象我的實現就可以使用Integer(Bookmark1^)來使用。另外,按照我的實現,GetRecNo也可以通過對ActiveBuffer(記錄當前活動的緩沖區)的訪問來獲得的。
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved