熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

用ADO.NET處理層次數據

2013-11-13 09:59:52  來源: .NET編程 

  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
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.