茫茫網海中的冷日
         
茫茫網海中的冷日
發生過的事,不可能遺忘,只是想不起來而已!
 恭喜您是本站第 1672156 位訪客!  登入  | 註冊
主選單

Google 自訂搜尋

Goole 廣告

隨機相片
IMG_00048.jpg

授權條款

使用者登入
使用者名稱:

密碼:


忘了密碼?

現在就註冊!

Dot Net? : [轉貼]輕鬆玩轉Typed DataSet

發表者 討論內容
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]輕鬆玩轉Typed DataSet
輕鬆玩轉 Typed DataSet, Part I

Written by: Rickie Lee

Dec. 07, 2004

Typed DataSet 與一般 DataSet 的簡單比較: 1. Typed DataSet 直接繼承 DataSet Class, 是一個特殊的 DataSet 類型 . 2. 通過 Typed DataSet ,可以方便直接地獲取 tables filelds. 3. 每一個 DataTable Typed DataSet 的一個屬性 . 4. 同樣地,每一個 Field
Data Row 的一個屬性 . 5. 使用 Typed DataSet ,不僅語法簡潔,而且在編譯期間進行類型檢查。 關於 Typed DataSet 的優點與缺點,及其在分布式應用系統中作用,請參考《 分布式應用架構中的數據傳輸對象( DTO 》。

一、創建 Typed DataSet

這裡演示 XSD 架構文件創建有類型的 DataSet 過程。 要使用 Visual Studio .NET XSD 架構文件創建有類型的 DataSet ,請執行以下步驟:

1.
Visual Studio .NET
中,創建一個新項目或打開一個現有項目。

2. 為項目添加一個現有的 XSD 架構,或在組件設計器中創建一個新的 XSD 架構。

從上圖可以發現, Typed DataSet 的後綴為 .xsd ,因為 Typed DataSet 的源文件是 XML Schema 文檔。 XSD 文件不僅包含 table column 名稱,而且包含 keys, relationships
constraints 信息。

3. 使用Server Explorer打開相應的Database,然後通過拖拉tables到上述XSD文件。

下面以 Northwind Database 為例:

添加 Orders, Order Details 兩個表。 VS.Net IDE 不能自動檢測 Database 中表間關係,因此 Orders Order Details 兩個表之間在 XSD 文件沒有自動產生任何關係。

4. 手工建立表與表之間的關係

Toolbox 中拖拉一個新的 Relation
XSD 編輯界面,並彈出如下 Edit Relation windows form

通過上述 Edit Relation 界面,可以編輯 relationship 參數。

另外,也可以通過 Toolbox XSD 的編輯界面,增加 / 修改 table column 元素。


注意:示例中將上面的 Order Details 元素改名為 OrderDetails ,去除其中的空格,以免一些不必要的麻煩。

Schema (架構)菜單中,單擊 Generate DataSet (生成 DataSet Preview DataSet

為確認已創建該有類型的 DataSet ,可以在解決方案資源管理器中單擊 Show All Files (顯示所有文件)按鈕。 展開 XSD 架構文件的節點,確認存在一個與 XSD 架構相關聯的代碼文件。該代碼文件定義了新的有類型的 DataSet 類。


public class OrderDataSet : DataSet

…… Typed DataSet/OrderDataSet 直接繼承 DataSet Class.

二、使用 Typed DataSet

在使用上述 Typed DataSet 之前,先了解 OrderDataSet.XSD 文件內容。

如下是 Northwind Database Orders table 的架構元素:



上述 XML Schema 會生成 OrdersRow 這一對象名稱
OrderDataSet.OrdersRow
,還有一個名為 Orders DataRowCollection Class OrderDataSet.Orders )。

調用上述 Typed DataSet Code snippet

OrderDataSet theOrderDS = new OrderDataSet();

string strSelectOrders = "Select * From Orders ";

strSelectOrders += "Select * From [Order Details]";

SqlHelper.FillDataset(connStr, CommandType.Text, strSelectOrders, theOrderDS, new string[] {"Orders", "OrderDetails"});


StringBuilder strResults = new StringBuilder();

foreach(OrderDataSet.OrdersRow theOrder in theOrderDS.Orders)

{

strResults.Append(theOrder.OrderID.ToString() + " "

+ theOrder.CustomerID.ToString() + " "

+ theOrder.EmployeeID.ToString() + Environment.NewLine);

strResults.Append("Order Details: ");

strResults.Append(theOrder.GetChildRows("OrdertoOrderDetails").GetLength(0).ToString());

strResults.Append(Environment.NewLine);


}

txtResults.Text = strResults.ToString();

代碼比較簡單,上述代碼調用了 SqlHelper Class Microsoft Data Access Application Block )的 FillDataset 方法,來完成 DataSet 的填充。 FillDataSet 方法支持 Typed DataSet ,值得推薦使用。

Any questions or errors, please leave comments. Thanks.

. 4. 同樣地,每一個 Field Data Row 的一個屬性 . 5. 使用 Typed DataSet
,不僅語法簡潔,而且在編譯期間進行類型檢查。 關於 Typed DataSet 的優點與缺點,及其在分布式應用系統中作用,請參考《 分布式應用架構中的數據傳輸對象( DTO 》。

一、創建 Typed DataSet

這裡演示 XSD 架構文件創建有類型的 DataSet 過程。 要使用 Visual Studio .NET XSD 架構文件創建有類型的 DataSet ,請執行以下步驟:

1. Visual Studio .NET 中,創建一個新項目或打開一個現有項目。

2. 為項目添加一個現有的
XSD
架構,或在組件設計器中創建一個新的 XSD 架構。

從上圖可以發現, Typed DataSet 的後綴為 .xsd ,因為 Typed DataSet 的源文件是 XML Schema 文檔。 XSD 文件不僅包含 table column 名稱,而且包含 keys, relationships constraints 信息。

3. 使用Server Explorer打開相應的Database,然後通過拖拉tables到上述XSD文件。

下面以 Northwind Database 為例:

添加 Orders, Order Details 兩個表。 VS.Net IDE 不能自動檢測 Database 中表間關係,因此 Orders Order Details 兩個表之間在 XSD 文件沒有自動產生任何關係。

4. 手工建立表與表之間的關係

Toolbox 中拖拉一個新的 Relation XSD 編輯界面,並彈出如下 Edit Relation windows form


通過上述 Edit Relation 界面,可以編輯 relationship 參數。

另外,也可以通過 Toolbox XSD 的編輯界面,增加 / 修改 table column 元素。

注意:示例中將上面的 Order Details 元素改名為 OrderDetails ,去除其中的空格,以免一些不必要的麻煩。


Schema (架構)菜單中,單擊 Generate DataSet (生成 DataSet Preview DataSet

為確認已創建該有類型的 DataSet ,可以在解決方案資源管理器中單擊 Show All Files (顯示所有文件)按鈕。 展開 XSD 架構文件的節點,確認存在一個與 XSD 架構相關聯的代碼文件。該代碼文件定義了新的有類型的 DataSet 類。

public class OrderDataSet : DataSet

…… Typed DataSet/OrderDataSet 直接繼承 DataSet Class.


二、使用 Typed DataSet

在使用上述 Typed DataSet 之前,先了解 OrderDataSet.XSD 文件內容。

如下是 Northwind Database Orders table 的架構元素:



上述 XML Schema 會生成 OrdersRow 這一對象名稱 OrderDataSet.OrdersRow ,還有一個名為 Orders DataRowCollection Class
OrderDataSet.Orders
)。

調用上述 Typed DataSet Code snippet

OrderDataSet theOrderDS = new OrderDataSet();

string strSelectOrders = "Select * From Orders ";

strSelectOrders += "Select * From [Order Details]";

SqlHelper.FillDataset(connStr, CommandType.Text, strSelectOrders, theOrderDS, new string[] {"Orders", "OrderDetails"});

StringBuilder strResults = new StringBuilder();


foreach(OrderDataSet.OrdersRow theOrder in theOrderDS.Orders)

{

strResults.Append(theOrder.OrderID.ToString() + " "

+ theOrder.CustomerID.ToString() + " "

+ theOrder.EmployeeID.ToString() + Environment.NewLine);

strResults.Append("Order Details: ");

strResults.Append(theOrder.GetChildRows("OrdertoOrderDetails").GetLength(0).ToString());

strResults.Append(Environment.NewLine);

}


txtResults.Text = strResults.ToString();

代碼比較簡單,上述代碼調用了 SqlHelper Class Microsoft Data Access Application Block )的 FillDataset 方法,來完成 DataSet 的填充。 FillDataSet 方法支持 Typed DataSet ,值得推薦使用。

Any questions or errors, please leave comments. Thanks.

冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]輕鬆玩轉Typed DataSet, Part II
輕鬆玩轉 Typed DataSet, Part II

Written by: Rickie Lee

Dec. 08, 2004

本文繼續前面《 輕鬆玩轉 Typed DataSet, Part I 》,這裡演練如何通過批註( Annotations )來定製類型化 DataSet ,並調用定製的 Typed DataSet

三、通過批註( Annotations )來定製類型化 DataSet

批註使您能夠在不修改基礎架構的情況下修改類型化 DataSet 中元素的名稱。如果修改基礎架構中元素的名稱,則會使類型化
DataSet 引用不存在於數據源中的對象,並且會丟失對存在於數據源中的對象的引用。

利用批註,您可以使用更有意義的名稱來自定義類型化 DataSet 中對象的名稱,從而使代碼更易於閱讀,類型化 DataSet 更易於為客戶端使用,同時保持基礎架構不變。

VS.Net IDE 默認的 DataSet 窗口切換到 XML 窗口。

1. 默認創建的 VS.Net IDE 自動生成的 Orders table 的架構元素



上述 XML Schema 會生成 OrdersRow 這一對象名稱 OrderDataSet.OrdersRow ,還有一個名為 Orders DataRowCollection Class
OrderDataSet.Orders )。

通過批註架構並標識 DataRow DataRowCollection 對象的新名稱,使上述對象名稱更有意義。

首先需要在 schema header 中增加 namespace 引用,允許定製元素屬性,如下所示:

< xs:schema id ="AnnotationTypedDataset" targetNamespace ="http://tempuri.org/AnnotationTypedDataset.xsd"

elementFormDefault ="qualified" attributeFormDefault ="qualified" xmlns
="http://tempuri.org/AnnotationTypedDataset.xsd"

xmlns : mstns ="http://tempuri.org/AnnotationTypedDataset.xsd" xmlns : xs ="http://www.w3.org/2001/XMLSchema"

xmlns : msdata ="urn:schemas-microsoft-com:xml-msdata" xmlns : codegen ="urn:schemas-microsoft-com:xml-msprop" >

下面是上一架構的批註版本:




Order 的值指定為 typedName 將生成 DataRow 對象名稱 Order 。將 Orders 的值指定為 typedPlural 則會保留 DataRowCollection 名稱 Orders

下表顯示可用的批註 (From MSDN):

批註

說明


typedName

對象的名稱。

typedPlural

對象集合的名稱。

typedParent

對像在父關係中被引用時的名稱。

typedChildren

用於從子關係中返回對象的方法的名稱。

nullValue

如果基礎值為 DBNull
,則為值。有關 nullValue 批註的信息,請參見下表。默認為 _throw

下表顯示可為 nullValue 批註指定的值 FROM MSDN :


nullValue

說明

替換值

指定要返回的值。所返回的值必須匹配該元素的類型。例如,使用 nullValue="0" 可為空整數字段返回 0

_throw

引發異常。這是默認值。

_null

如果遇到基元類型,則返回空引用或引發異常。

_empty

對於字符串返回 String.Empty ;否則,返回從空構造函數創建的對象。如果遇到基元類型,則引發異常。

下面是 OrderDetails 架構的批註版本:


通過
typedParent typedChildren 屬性更改 Order/OrderDetails 對象的引用方法:

< xs:keyref name ="OrdertoOrderDetails" refer ="AnnotationTypedDatasetKey1" codegen:typedParent="Order" codegen:typedChildren="GetOrderDetails">

< xs:selector xpath =".//mstns:OrderDetails" />

< xs:field xpath ="mstns:OrderID" />

xs:keyref
>

這樣 Order 對象就產生一個 GetOrderDetails() 方法,沿著 Relationship 向下導航到 OrderDetail 對象, OrderDetails 對象生成一個 Order() 方法,沿著 Relationship 向上導航到 Order 對象。

四、調用定製的 Typed DataSet

如下是調用上述通過 Annotation 定製的 Typed DataSet Code snippet 如下所示:

AnnotationTypedDataset theOrderDS = new AnnotationTypedDataset();


string strSelectOrders = "Select * From Orders ";

strSelectOrders += "Select * From [Order Details]";

SqlHelper.FillDataset(connStr, CommandType.Text, strSelectOrders, theOrderDS, new string[] {"Orders", "OrderDetails"});

StringBuilder strResults = new StringBuilder();

foreach( AnnotationTypedDataset.Order theOrder in theOrderDS.Orders )

{

strResults.Append(theOrder.OrderID.ToString() + " "

+ theOrder.CustomerID.ToString() + " "

+ theOrder.EmployeeID.ToString() + Environment.NewLine);

strResults.Append("Order Details: ");

strResults.Append(theOrder.GetChildRows("OrdertoOrderDetails").Length.ToString() + " ");

strResults.Append(theOrder. GetOrderDetails ().Length.ToString());

strResults.Append(Environment.NewLine);

}

txtResults.Text = strResults.ToString();

代碼比較簡單,上述代碼調用了 SqlHelper Class Microsoft Data Access Application Block )的 FillDataset 方法,來完成 DataSet 的填充。與調用默認的 Typed DataSet 代碼相比較有細微差別。

Any questions or errors, please leave comments below. Thanks.

References:

1. MSDN

2. Rickie, 輕鬆玩轉 Typed DataSet, Part I

冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]輕鬆玩轉Typed DataSet, Part III
輕鬆玩轉 Typed DataSet, Part III

Written by: Rickie Lee

Dec. 10, 2004

本文繼續前面《 輕鬆玩轉 Typed DataSet, Part II 》,這裡演練在使用 Typed DataSet 過程中,如何有效地 Debug 程序中出現的錯誤。最常見的錯誤 Exception 應該是:

An unhandled exception of type 'System.Data.ConstraintException' occurred in system.data.dll


Additional information: Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.

顯然,通過 VS.Net IDE 顯式的上述 Exception 信息,很難判斷到底錯誤在什麼地方。這裡提供的一個有效的方法來 Debug ,盡快找到 Bug 的真正原因,並加以解決。

private void PrintAllErrs(DataSet myDataSet)

{

DataRow[] rowsInError;

foreach(DataTable myTable in myDataSet.Tables)

{

// Test if the table has errors. If not, skip it.


if(myTable.HasErrors)

{

// Get an array of all rows with errors.

rowsInError = myTable.GetErrors();

Console.WriteLine(myTable.TableName + " " + rowsInError.Length.ToString()

+ " " + rowsInError[0].RowError);

// Print the error of each column in each row.

/*for(int i = 0; i< rowsInError.Length; i++)

{

foreach(DataColumn myCol in myTable.Columns)


{

Console.WriteLine(myCol.ColumnName + " " +

rowsInError[i].GetColumnError(myCol));

}

// Clear the row errors

rowsInError[i].ClearErrors();

}*/

}

}

}

通過上面的 PrintAllErrs() 方法,明確輸出錯誤的信息,其中註釋的 for 語句根據時間情況來確定是否需要。


下面演示如何使用上述 Code snippet ,下面的代碼與前面的 post 輕鬆玩轉 Typed DataSet, Part II 》相關,更詳細的信息,請參考《 輕鬆玩轉 Typed DataSet, Part II 》:

AnnotationTypedDataset theOrderDS = new AnnotationTypedDataset();

try

{

string strSelectOrders = "Select top 5 * From Orders ";

strSelectOrders += "Select * From [Order Details]";


SqlHelper.FillDataset(connStr, CommandType.Text, strSelectOrders, theOrderDS, new string[] {"Orders", "OrderDetails"});

StringBuilder strResults = new StringBuilder();

foreach(AnnotationTypedDataset.Order theOrder in theOrderDS.Orders)

{

strResults.Append(theOrder.OrderID.ToString() + " "

+ theOrder.CustomerID.ToString() + " "

+ theOrder.EmployeeID.ToString() + Environment.NewLine);

strResults.Append("Order Details: ");


strResults.Append(theOrder.GetChildRows("OrdertoOrderDetails").Length.ToString() + " ");

strResults.Append(theOrder.GetOrderDetails().Length.ToString());

strResults.Append(Environment.NewLine);

}

txtResults.Text = strResults.ToString();

}

catch

{

PrintAllErrs(theOrderDS);

}

異常 Exception 輸出結果:


OrderDetails 2141 ForeignKeyConstraint OrdertoOrderDetails requires the child key values (10253) to exist in the parent table.

包含有錯誤的 table name ,錯誤的 Rows 總數,並輸出第 1 行錯誤的具體信息,如果要輸出所有行的錯誤信息,則需要開發 PrintAllErrs() 方法的 for 循環。

通過上面輸出的錯誤信息,可以很快發現是上面的 SQL 語句有問題,子表 OrderDetails key 值在父表 Orders 不存在。

Any questions or errors, please leave comments below. Thanks.


References:

1. Rickie, 輕鬆玩轉 Typed DataSet, Part I

2. Rickie, 輕鬆玩轉 Typed DataSet, Part II

3. MSDN, DataTable.GetErrors Method, http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDataDataTableClassGetErrorsTopic.asp

冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]輕鬆玩轉Typed DataSet, Part IV
輕鬆玩轉 Typed DataSet, Part IV

Written by: Rickie Lee

Dec. 11, 2004

本文繼續前面的 Typed DataSet 系列文章(輕鬆玩轉 Typed DataSet, Part 1-3 ),這裡闡述 Typed DataSet 相關文件及其作用和 Typed DataSet 在多層企業級系統中的應用等等。

1. Typed DataSet 相關文件及其作用

按照《
輕鬆玩轉 Typed DataSet, Part I
》中所提及的 使用 Visual Studio .NET XSD 架構文件創建有類型的 DataSet 一個典型的 Typed DataSet 包含如下 3 個文件,通過點擊右邊 Solution Explorer 上的 Show all files 可以看到:

1 XSD

XSD 文件存放定義 typed DataSet Schema XML 內容,可以通過 Annotation
來定製 typed DataSet ,更詳細信息請參考《 輕鬆玩轉 Typed DataSet, Part II 》。

2 Class file (如 CS

Class 文件創建 typed DataSet ,一般由 VS.Net xsd.exe 命令行工具自動生成,包括繼承 DataSet Typed DataSet Class 信息。該 class 文件實際上包括一系列繼承並擴展
DataSet, DataRow EventArgs classes ,因為上述繼承關係, Typed DataSet 仍然保留有 untyped DataSet 的所有特性,並沒有丟失任何特性。

如在引用 Typed DataSet DataTable 對象時,你既可以使用 Tables 集合對象,也可以直接引用對應的屬性 Property ,代碼如下所示:

AnnotationTypedDataset.Orders

AnnotationTypedDataset.Tables[「Orders」]


3 XSX

XSX XML Schema Extended )文件由 XML Schema Designer 自動生成,包含 Designer 界面上布局或可視化信息。

2. Typed DataSet 在多層企業級系統中的應用

當在多層的企業級應用系統中採用 Typed DataSet 時,通常要求 Typed DataSet 在全部或多數 tiers 中可以使用。因此,一般情況下將 Typed DataSet 及其相關文件存放最低的層次,這樣其他引用該層的項目和 assemblies 就可以引用 Typed DataSet
對象了。

Typed DataSet 的用法示例:

(1) 定位 Typed DataSet 中的 OrderDetailsRow 數據行

OrdersDataSet.OrderDetailsRow oRow;

oRow = oDs.OrderDetails.FindByOrderIDProductID(

nOrderID_OrderDetail, nProductID_Original);

(2) 檢測是否列 Column 中包含 null

if(!oDs.Orders[0].IsOrderDateNull())

{


oDs.Orders[0].SetOrderDateNull();

}

(3) 循環 Orders 所有數據行及其關聯的 Order Details 記錄

foreach(OrdersDataSet.OrdersRow oOrderRow in oDs.Orders)

{

Debug.WriteLine("OrderID = " + oOrderRow.OrderID);

foreach(OrdersDataSet.OrderDetailsRow oOrderDetailRow in

oOrderRow.GetOrderDetailsRows())

{


Debug.WriteLine(" — " + oOrderDetailRow.ProductName);

}

}

需要注意的是:如果後台的 Database structure 發生變化,則需要同步 Typed DataSet Schema 信息。在這樣情況下,即使採用 Untyped DataSet ,你也需要改變一些 Client 端代碼。但使用 Typed DataSet 的好處是,編譯器能夠標識出用戶代碼中大部分需要修改的地方,因為編譯器能夠對 Typed DataSet 在編譯期間進行類型安全檢查,而 untyped DataSet 則只能在 runtime 期間發現錯誤並拋出異常。


References:

1. Rickie, 輕鬆玩轉 Typed DataSet, Part I

2. Rickie, 輕鬆玩轉 Typed DataSet, Part II

3. Rickie, 輕鬆玩轉 Typed DataSet, Part III

4. John Papa, Efficient Coding With Strongly Typed DataSets,
http://msdn.microsoft.com/msdnmag/issues/04/12/DataPoints/default.aspx

前一個主題 | 下一個主題 | 頁首 | | |



Powered by XOOPS 2.0 © 2001-2008 The XOOPS Project|