很多人都在問,ClIEntDataSet如何才能在不連接數據庫得情況下,用程序創建起來,並打開數據集。
在研究了一下TClientDataSet數據集後,發現如果要讓ClIEntDataSet打開的話(Open),必須滿足三個條件中的一個:
這三個條件是TClIEntDataSet的Active屬性的幫助中說的。思考一下,第一和第二基本被排除,我如果有了現成的數據集,還要創建干嗎?第三個又不是那麼容易,你哪知道文件的格式是什麼呢?
那到底該怎麼做呢?
突然想起TClIEntDataSet中支持InternalCalc(內部計算)字段。內部計算字段可以在設計期加進去,或者也可以在運行期動態加入。我們為了方便,就在設計期加入。見下圖:
可以通過雙擊控件(TClientDataSet)進入字段編輯器,然後右鍵選擇“New Field”命令,得到如圖所示的界面。填寫Name,Type和FIEldType。
記住:FIEldType一定要是“InternalCalc”。如此反復,你可以選擇添加多個字段。
打開!報錯:“ProviderName”或Data沒有賦值。
這個方法不正確,既然要Data,我嘗試著,從其它ClIEntDataSet的Data屬性賦值上。得到結果是:自己新建的字段和數據源的字段都顯示。
我又進行了進一步的嘗試:那就是讓這個有著新建的字段和原有字段的ClientDataSet的Data賦值到另一個新的ClIEntDataSet上,卻發現新建的字段沒有進入。
總得來說,這次嘗試是失敗的,不過有如下總結:
又是XML!ClIEntDataSet本就是斷開連接的數據集控件,應此提供了將數據緩存到磁盤的功能SaveToFile(),其詳細聲明如下:
procedure SaveToFile(const FileName: string = ''; Format: TDataPacketFormat = dfBinary);
注意到其中的TDataPacketFormat。它是個枚舉類型,全部的枚舉值如下:
TDataPacketFormat = (dfBinary, dfXML, dfXMLUTF8);
大家可能注意到了,dfBinary和dfXMLUTF8都不是我們需要關心的,關心一下我們的dfXML格式。這是個讓人興奮的消息。有了XML,我們就可以查看ClIEntDataSet的MetaData的定義,而且更有了修改的可能!
調用一下SaveToFile功能,注意保存格式為dfXML。打開文件,如下顯示:
<?XML version="1.0" standalone="yes" ?> - <DATAPACKET Version="2.0"> - <METADATA> - <FIELDS> - <FIELD attrname="NormInfoID" fieldtype="i4"> <PARAM Name="PROVFLAGS" Value="7" Type="i4" Roundtrip="True" /> </FIELD> <FIELD attrname="Description" fieldtype="string.uni" WIDTH="160" /> <FIELD attrname="NormInfoVal" fieldtype="string.uni" WIDTH="510" /> <FIELD attrname="NewField" fieldtype="i4" /> <FIELD attrname="Boolean" fieldtype="Boolean" /> <FIELD attrname="Date" fieldtype="date" /> <FIELD attrname="Time" fieldtype="time" /> </FIELDS> <PARAMS DEFAULT_ORDER="1" PRIMARY_KEY="1" /> </METADATA> <ROWDATA /> </DATAPACKET>
看這個全部的,比較混亂,先看一下結構:
<?XML version="1.0" standalone="yes" ?> - <DATAPACKET Version="2.0"> + <METADATA> <ROWDATA /> </DATAPACKET>
這下比較清楚了:
整個XML定義為一個DataPacket,DataPacket包括兩個部分:MetaData和RowData。顯然對我們來說,RowData可以忽視,到時候將RowData的節點清空就是。而MetaData呢?
看看全部的XML格式,可以看出:MetaData包括FIElds和Params。即字段和數據集參數。
先重點考慮Fields。看一下FIEld節點的定義,大概可以看出一些:
下面我們來研究一下字段類型,我想這也是最主要的!其它屬於高級用法。
見上表,這是我在SQLServer2000中,將所有類型的字段都用上,然後在ClientDataSet中得到的,類型對應關系。注意到有SubType屬性,來幫助決定類型。其中沒有值的單元格,表示該屬性沒有用到。寬度值中,除了UniqueIdentifIEr是38外,其余都是采用系統默認寬度。
分析一下這一張表,可以得到如下一些特點:
注意到某些字段的定義下有節點:
<PARAM Name="PROVFLAGS" Value="7" Type="i4" Roundtrip="True" />
先來解釋一下“PROVFLAGS”,在Delphi的源碼裡查找可以發現其實就是對應著TFIEld的屬性ProviderFlags,那麼7也就是好理解的了。
看TProviderFlag和TProviderFlags的定義
TProviderFlag = (pfInUpdate, pfInWhere, pfInKey, pfHidden); TProviderFlags = set of TProviderFlag;
既然是集合,那麼7很顯然就是一個集合的整數表示:按順序排的話,7其實就是表示結合[pfInUpdate, pfInWhere, pfInKey]。
不過不知道為什麼,查看TFIEld的屬性,pfInKey不在集合中。
看看
<PARAMS DEFAULT_ORDER="1" PRIMARY_KEY="1" />
可以看出DEFAULT_ORDER和PRIMARY_KEY的意思,但是後面的值呢?研究之後,發現,它是主鍵或索引字段的Index。如果同時兩個字段都是索引,那麼它的格式是:"1 2",中間采用空格隔開。
好了,格式大概都知道了,現在問題是如何轉載到ClIEntDataSet呢?
文件是可以,但是顯然不滿足我們當初的需求,在查看一下接口定義,發現除了LoadFromFile還有LoadFromStream。查看一下源碼,其實LoadFromFile就是調用了LoadFromStream。
好了,只要我們創建了這樣的XML流,就可以動態創建ClIEntDataSet了!
至於如何創建XML流,不在此討論了