ADONET 為數據在內存中的操作和儲存提供了一種新模式因此我們在處理層次數據時該換換腦了本文將對其獨到之處作一個簡單的描述
讀者要求基本掌握 Visual DataAdapter 和 DataSet
環境
[配置一]
操作系統 Windows 服務器
計算機 Dell Inspiron 筆記本
內存 mb
處理器 PIII MHz
工具 NET SDK Beta
數據庫 SQL 服務器 的 Pubs 數據庫
[配置二]
操作系統 Windows XP Professional
計算機Network! 筆記本
內存mb
處理器 PIII MHz
工具NET Final
數據庫MSDE 的 Pubs 數據庫
簡單的數據檢索
我們首先要做的是通過 SQLAdapter 向數據庫提交兩個查詢語句
本例中SQLAdapter 使用由兩個 select 語句組成的 SQL 命令分別向 Pubs 數據庫中的兩個 table 發出查詢請求
string sSQL = SELECT Pub_Id Title Price FROM; SELECT Pub_ID Pub_Name FROM Publishers
在 fill 模式下 SQLAdapter 將在查詢命令前插入 sp_executesql 再以 RPC 的形式一並提交給數據庫
Exec sp_executesql
NSELECT Pub_Id Title Price FROM Titles; SELECT Pub_ID Pub_Name FROM Publishers
數據庫也通過 RPC 返回兩個 rowset在 Dataset 中rowset 與基本表是一一對應的不幸的是在 fill 模式下無法對這些基本表命名相反它為所有基本表提供一個共同的基本名事實上基本名就是第一個基本表的名字隨後的基本表命名都是在基本名後面加上一個不同的數字以互相區別例如Titles Titles等但是通過簡單的屬性設置就能給所有基本表命名了
daTestFill(dsTest Titles)
dsTestTables[]TableName = Publishers
這種顯式命名有助於基本表的處理和引用
關於存儲過程
在 ADONET 中如何使用存儲過程?天太復雜了!但我還是要簡單地介紹一兩點為以後討論層次數據作個鋪墊吧!
利用存儲過程同時獲取多個行集(rowset)的方法有兩種
第一種方法是一個存儲過程多個輸出行集例如我們可以在前一個例子的基礎上增加一個存儲過程將兩條 select 語句包含進去
CREATE PROCEDURE [dbo][TitlesPERPublisher]
AS
Begin
SELECT Pub_Id Title Price FROM Titles
SELECT Pub_ID Pub_Name FROM Publishers
End
夠簡單吧!這段代碼提交兩個 select 語句因而將返回兩個行集
為了提高效率我們可以借助 dataAdapter 的 Selectcommand 屬性設置指令類型為
CommandTypeStoredProcedure
daHDAta = new SqlDataAdapter(sSQLCmd cnstring)
dahDataSelectCommandCommandType = CommandTypeStoredProcedure
因為這樣可以指示 dataAdapter 使用效率較高的 tsql 語句 Exec 執行存儲過程如果省略這一步dataAdapter 就以低效的 sp_executesql 執行它了
第二種方法是兩個存儲過程兩個輸出行集然而此法造成數據來回傳遞況且無論數據轉輸抑或 RPC 建立都是耗時過程效率自然大打折扣
由此我們得出結論爭取用一個存儲過程返回全部行集 就本例而言最簡單的做法莫過於用一個新過程捆綁兩個存儲過程此法或許不盡完美但是別忘了這是最簡單的
至於如何在應用程序和 中同時調用兩個存儲過程由於篇幅有限請自行參考有關 sqlCommand 對象的文章
關系
為了處理現實中的層次數據必須理清基本表之間的關系借助 Dataset 的關系集合很容易建立起關系語法簡潔明了應該不成問題
public void Add(DataRelation);
public virtual DataRelation Add(DataColumn DataColumn);
public virtual DataRelation Add(DataColumn[] DataColumn[]);
public virtual DataRelation Add(string DataColumn DataColumn);
public virtual DataRelation Add(string DataColumn[] DataColumn[]);
public virtual DataRelation Add(string DataColumn DataColumn bool);
public virtual DataRelation Add(string DataColumn[] DataColumn[] bool);
為了建立關系必須提供一個關系名字符串和至少兩個列如果關系已經存在或者列有問題 (比如它們不存在)則運行環境將產生一個異常詳情請見 NET 框架 SDK
下列代碼在現有的基本表之間新增了一個簡單的關系
dsTestRelationsAdd(PubTitles
dsTestTables[Publishers]Columns[Pub_ID]
dsTestTables[Titles]Columns[Pub_ID])
此代碼在名為 PubTitles 的關系集合中創建了一個 relation 對象和一個關系PublishersPub_ID 是父表而 TitlesPub_id 是子表
顯示數據
為了選取子列datarow 對象提供了一個 GetChildRows 方法它的參數是關系名或許關系對象名
public DataRow[] GetChildRows(DataRelation);
public DataRow[] GetChildRows(string);
public DataRow[] GetChildRows(DataRelation DataRowVersion);
public DataRow[] GetChildRows(string DataRowVersion);
類似的方法還有 GetParentRow 和 GetParentRows 它們根據子列返回父列的名字
現在有了 GetChildRows 方法就向數據進軍吧! GetChildRows 返回一個 DataRowCollection 對象後者的父類 InternalDataCollectionBase 是對 ICollection 和 IEnumerable 的具體實現
接下來的循環處理只是舉手之勞了下列代碼演示了顯示數據關系的一種簡單方法
foreach(DataRow drPublisher in dtPublishersRows)
{
ConsoleWriteLine(drPublisher[Pub_Id] + \t + drPublisher[Pub_Name]);
ConsoleWriteLine(=====================);
foreach(DataRow drTitle in drPublisherGetChildRows(PubTitles))
{
ConsoleWrite(drTitle[Title] + \t);
ConsoleWrite((drTitle[price]ToString() != null ? drTitle[price] : n/a));
}
}
當然也可明確指定一個 relation 對象
DataRelation drPubsTitles = dsHDataRelationsAdd(PubTitles
dtPublishersColumns[Pub_ID]
dsHDataTables[Titles]Columns[Pub_ID]);
foreach(DataRow drPublisher in dtPublishersRows)
{
ConsoleWriteLine(drPublisher[Pub_Id] + \t + drPublisher[Pub_Name]);
ConsoleWriteLine(=====================);
foreach(DataRow drTitle in drPublisherGetChildRows(drPubsTitles))
{
ConsoleWrite(drTitle[Title] + \t);
ConsoleWrite((drTitle[price]ToString() != null ? drTitle[price] : n/a));
}
}
ADONET 能讓程序員在數據表中創建自定義視圖這是由 DataView 類實現的
public class DataView : MarshalByValueComponent IBindingList
IList ICollection IEnumerable ITypedList ISupportInitialize
當然限於篇幅這裡僅僅列舉了部分函數
數據視圖提供了兩個有趣的屬性RowFilter 和 Sort RowFilter 與 ADO recordset 對象的 Filter 屬性相似它相當於與 SQL 語法中的 WHERE 語句能夠篩去匹配的列
dtPublishersDefaultViewRowFilter=Pub_ID < ;
最終得到的列被置於 DataRowView 集合中因此能用 for each 語句循環處理它們
Sort 屬性用於指定輸出數據的排序方式它與 SQL 語法中的 ORDER BY 命令相似
dtPublishersDefaultViewSort=PUB_ID Desc;
每個基本表對應一個 DataView 對象上述DefaultView 就是其屬性於是只需做些小小的修改我們就能有選擇地循環顯示數據了
foreach(DataRow drPublisher in dtPublishersRows)
{
ConsoleWriteLine(drPublisher[Pub_Id] + \t + drPublisher[Pub_Name]);
ConsoleWriteLine(=====================);
foreach(DataRow drTitle in drPublisherGetChildRows(PubTitles))
{
ConsoleWrite(drTitle[Title] + \t);
ConsoleWrite((drTitle[price]ToString() != null ? drTitle[price] : n/a));
}
}
結論
ADONET 大大簡化了層次數據的處理並且提供了改良的方案
讀過本文是否躍躍欲試呢?若要追求更強的功能恐怕還得另請高明了
本文沒有考慮性能優化因為我們討論的 SDK 還是 beta 版
From:http://tw.wingwit.com/Article/program/net/201311/12236.html