使用.NET存儲(chǔ)XML數(shù)據(jù)的方法
這三種技術(shù)中的每一種都是為特定的目的設(shè)計(jì)的。XML Bulk Load把來自很大的XML文檔的數(shù)據(jù)存儲(chǔ)在SQL Server中;Updategrams執(zhí)行SQL Server數(shù)據(jù)的優(yōu)化更新(優(yōu)化更新是沒有鎖(lock)的更新,在這種更新中系統(tǒng)檢測(cè)是否有其它用戶在原來讀取數(shù)據(jù)后改變了它);OpenXML提供了人們熟悉的XML數(shù)據(jù)關(guān)系訪問方法。
在這三種技術(shù)中,OpenXML是最靈活的,因?yàn)樗峁┝艘粋€(gè)編程模型(T-SQL),在把XML數(shù)據(jù)存儲(chǔ)在SQL Server數(shù)據(jù)庫之前,你可以使用這種編程模型在XML數(shù)據(jù)上編寫業(yè)務(wù)規(guī)則或執(zhí)行計(jì)算邏輯。但是,由于OpenXML是一種基于服務(wù)器的技術(shù),如果你頻繁的使用它或者有大量的文檔,它會(huì)降低SQL Server的性能。不過,如果你采用了微軟.net框架組件,你就可以使用ADO.NET的數(shù)據(jù)集繞開這些性能和可伸縮性方面的限制,ADO.NET數(shù)據(jù)集賦予你一個(gè)強(qiáng)大的技術(shù)--為把XML數(shù)據(jù)存儲(chǔ)在SQL Server包含了一個(gè)完整的編程模型。
數(shù)據(jù)集、數(shù)據(jù)表和XML映射
你可以使用數(shù)據(jù)集簡(jiǎn)單地從SQL Server中生成XML查詢結(jié)果。通過提供一種可以在客戶端和中間層計(jì)算機(jī)上使用的關(guān)系數(shù)據(jù)緩存(cache),數(shù)據(jù)集能夠載入和維護(hù)多種數(shù)據(jù)源(包括SQL Server、其它的關(guān)系型數(shù)據(jù)庫和XML)中的數(shù)據(jù)。
當(dāng)你從XML文檔中載入一個(gè)數(shù)據(jù)集的時(shí)候,該數(shù)據(jù)集必須把存儲(chǔ)在層次XML表現(xiàn)(representation)中的數(shù)據(jù)映射成數(shù)據(jù)集的關(guān)系表現(xiàn)。例如,如果你的XML文檔包含一個(gè)Order元素列表,而它又有一個(gè)作為子元素的嵌套的LineItem元素,那么通常這個(gè)文檔被映射成關(guān)系表現(xiàn)中的Orders和LineItems數(shù)據(jù)表。這種映射的目的與OpenXML使用Xpath查詢構(gòu)造XML文檔上的關(guān)系視圖的方法的目的是一樣的。但是與使用Xpath規(guī)范不同,數(shù)據(jù)集有自己的映射數(shù)據(jù)的方式。
數(shù)據(jù)集使用XML大綱定義(XSD)大綱把數(shù)據(jù)從XML文檔映射到數(shù)據(jù)集的關(guān)系數(shù)據(jù)緩存中。數(shù)據(jù)集為你提供了指定映射XML數(shù)據(jù)的大綱的兩種方法。首先,你可以引用一個(gè)定義了XML文檔中使用的元素,屬性和關(guān)系的XSD大綱。另一種方法是,你可以直接從文檔的結(jié)構(gòu)中推理大綱。換句話說,數(shù)據(jù)集可以通過檢查XML文檔的結(jié)構(gòu)和內(nèi)容建立大綱。
當(dāng)你引用XSD大綱的時(shí)候,數(shù)據(jù)集使用這個(gè)大綱中定義的元素、屬性與元素之間的關(guān)系來構(gòu)造關(guān)系數(shù)據(jù)緩存中的數(shù)據(jù)表、數(shù)據(jù)列和數(shù)據(jù)關(guān)系,你可以使用這個(gè)數(shù)據(jù)緩存存儲(chǔ)被映射的XML數(shù)據(jù)。我談到關(guān)系數(shù)據(jù)緩存中的結(jié)構(gòu)或大綱的時(shí)候,一般把它稱為數(shù)據(jù)緩存的形式。當(dāng)數(shù)據(jù)集處理大綱的時(shí)候,它會(huì)應(yīng)用一組規(guī)則,這種規(guī)則與映射大綱中沒有指定注解時(shí)Updategrams 和XML Bulk Load使用的默認(rèn)映射規(guī)則相似,數(shù)據(jù)集使用這種規(guī)則建立數(shù)據(jù)集用于存儲(chǔ)被映射的XML數(shù)據(jù)的表。數(shù)據(jù)集的映射規(guī)則概述如下:
· 復(fù)合元素--即包含其它元素或?qū)傩缘脑?-被映射成表。
· 屬性和簡(jiǎn)單值(simple-valued)子元素--只包含數(shù)據(jù),不包含其它元素或?qū)傩缘脑?-被映射成列。
· 數(shù)據(jù)類型從XSD類型映射為.NET類型?!?nbsp;
推理(Inference)是一種快速、方便的把XML文檔載入數(shù)據(jù)集的方法。表、列和關(guān)系都是"自我測(cè)量"(introspection)自動(dòng)建立的,"自我測(cè)量"是數(shù)據(jù)集檢查XML文檔的結(jié)構(gòu)和內(nèi)容的過程。盡管使用推理明顯減少了你的編程負(fù)擔(dān),但是它也給你的實(shí)現(xiàn)帶來了不可預(yù)測(cè)性,因?yàn)閷?duì)XML文檔的很小的改動(dòng)可能引起數(shù)據(jù)集建立不同形式的表。這些形式的改變可能引起你的應(yīng)用程序意外中斷。因此,我推薦你一般為應(yīng)用程序引用一個(gè)大綱,建立原型的時(shí)候限制推理的使用。
現(xiàn)在讓我們看一看如何使用大綱建立一個(gè)可用于更新SQL Server數(shù)據(jù)庫的客戶端數(shù)據(jù)集數(shù)據(jù)緩存的例子。
映射XML訂單
假定你在編寫一個(gè)接受用戶訂單的應(yīng)用程序,訂單是XML格式的,它的XSD大綱如圖1定義。該大綱定義了三種復(fù)合類型,分別提供訂單的客戶數(shù)據(jù)、訂單數(shù)據(jù)和線性數(shù)據(jù)項(xiàng)。一個(gè)頂層Customer元素定義了XML文檔的根。這個(gè)封閉的系統(tǒng)定義了元素之間的關(guān)系:Order元素包含了一個(gè)LineItem元素,Customer元素包含一個(gè)Order元素。圖2顯示了符合圖1定義的大綱的一個(gè)XML文檔實(shí)例。
圖1:XSD大綱
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="urn:Sep2003Example" elementFormDefault="qualified"
xmlns="urn:Sep2003Example"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
?。紉s:complexType name="OrderType">
?。紉s:sequence>
<xs:element name="OrderID" type="xs:integer" />
?。紉s:element name="LineItem" type="LineItemType" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="LineItemType">
?。紉s:sequence>
<xs:element name="ProductID" type="xs:int" />
?。紉s:element name="Quantity" type="xs:int" />
?。紉s:element name="UnitPrice" type="xs:decimal" />
?。?xs:sequence>
</xs:complexType>
<xs:complexType name="CustomerType">
?。紉s:sequence>
?。紉s:element name="CustomerID" type="xs:string" />
?。紉s:element name="Order" type="OrderType" />
?。?xs:sequence>
</xs:complexType>
<xs:element name="Customer" type="CustomerType">
</xs:element>
</xs:schema>
圖2:一個(gè)XML文檔示例
<?xml version="1.0" ?>
?。糃ustomer xmlns="urn:Sep2003Example">
<CustomerID>ALFKI</CustomerID>
?。糚O>9572658</PO>
?。糀ddress>
?。糞treet>One Main Street</Street>
?。糃ity>Anywhere</City>
?。糞tate>NJ</State>
?。糧ip>08080</Zip> </Address>
?。糘rder>
?。糘rderID>10966</OrderID>
<LineItem>
?。糚roductID>37</ProductID>
?。糢nitPrice>26.50</UnitPrice>
<Quantity>8</Quantity>
?。糄escription>Gravad lax</Description>
</LineItem>
?。糒ineItem>
<ProductID>56</ProductID>
?。糢nitPrice>38.00</UnitPrice>
?。糛uantity>12</Quantity>
<Description>Gnocchi di nonna Alice</Description>
?。?LineItem>
?。?Order>
?。?Customer>
列表1中顯示的C#代碼使用ReadXmlSchema方法把圖1中的大綱載入一個(gè)叫作orderDS的數(shù)據(jù)集中。ReadXmlSchema建立了三個(gè)數(shù)據(jù)表,它們分別與大綱中定義的Customer、Order和LineItem元素對(duì)應(yīng)。因此你可以驗(yàn)證這個(gè)大綱在關(guān)系數(shù)據(jù)緩存中建立了預(yù)期的表,printDSShape方法把每個(gè)表的名稱寫到控制臺(tái)上,后面跟著列的列表和每列的數(shù)據(jù)類型。
列表1: 建立關(guān)系數(shù)據(jù)緩存的C#代碼
using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Xml;
public class XMLMap
{
public static void Main()
{
// 建立數(shù)據(jù)集和讀取大綱
DataSet orderDS = new DataSet("CustOrder");
orderDS.ReadXmlSchema("CustOrderLitem.xsd");
// 打印數(shù)據(jù)集的形式
printDSShape(orderDS);
// 把一個(gè)XML格式的訂單讀入數(shù)據(jù)集
orderDS.ReadXml("Order.xml",System.Data.XmlReadMode.IgnoreSchema);
// 打印數(shù)據(jù)集中的數(shù)據(jù)
printDSData(orderDS);
// 此處插入業(yè)務(wù)規(guī)則和數(shù)據(jù)庫更新邏輯
}
private static void printDSShape(DataSet ds)
{
foreach (DataTable dt in ds.Tables)
{
Console.WriteLine("{0}",dt.TableName);
// 打印列的名稱和類型
foreach (DataColumn dc in dt.Columns)
Console.WriteLine("\t{0}\t{1}",dc.ColumnName,dc.DataType.ToString());
}
}
private static void printDSData(DataSet ds)
{
foreach (DataTable dt in ds.Tables)
{
Console.WriteLine("\n{0}:", dt.TableName);
// 打印列的頭
foreach (DataColumn dc in dt.Columns)
Console.Write("{0}\t",dc.ColumnName);
Console.WriteLine("");
// 輸出數(shù)據(jù)
foreach (DataRow dr in dt.Rows)
{
foreach(DataColumn dc in dt.Columns)
System.Console.Write("{0}\t",dr[dc]);
System.Console.WriteLine("");
}
}
}
}
仔細(xì)查看一下列的名稱。盡管大綱中沒有指定Customer_Id和Order_Id列,但是它們還是出現(xiàn)在數(shù)據(jù)表中。ReadXmlSchema給數(shù)據(jù)集自動(dòng)添加這些列。數(shù)據(jù)集把這些列用作外部鍵(foreign key),以模擬Customer元素與它的Order元素之間、Order元素與它的LineItem元素之間的關(guān)系。因?yàn)榈湫颓闆r下XML使用嵌套的關(guān)系代替了外部鍵,所以數(shù)據(jù)集自動(dòng)生成自己的主鍵、數(shù)據(jù)表之間的外部鍵,并把它們存儲(chǔ)在這些列中。
請(qǐng)同時(shí)仔細(xì)查看圖3中的數(shù)據(jù)類型--數(shù)據(jù)集已經(jīng)把來自XML大綱數(shù)據(jù)類型的數(shù)據(jù)類型映射為對(duì)應(yīng)的.net數(shù)據(jù)類型。當(dāng)你把XML文檔載入數(shù)據(jù)集的時(shí)候,該數(shù)據(jù)集把來自XML的每一個(gè)值轉(zhuǎn)換為對(duì)應(yīng)的.NET類型。
圖3:生成的數(shù)據(jù)類型和記錄
Customer
CustomerID System.String
Customer_Id System.Int32
order
orderID System.Int64
order_Id System.Int32
Customer_Id System.Int32
LineItem
ProductID System.Int32
Quantity System.Int32
UnitPrice System.Decimal
order_Id System.Int32
Customer:
CustomerID Customer_Id
ALFKI 0
order:
orderID order_Id Customer_Id
10966 0 0
LineItem:
ProductID Quantity UnitPrice order_Id
37 8 26.5 0
56 12 38 0
把大綱載入數(shù)據(jù)集之后,為了完成關(guān)系映射,你需要做的所有事情就是把XML數(shù)據(jù)載入該數(shù)據(jù)集。列表1的ReadXml方法打開叫作Order.xml的文件,該文件如圖2所示。接著,它把文件中的數(shù)據(jù)讀取到你剛才讀取大綱建立的數(shù)據(jù)集中的數(shù)據(jù)表里。你的XML訂單現(xiàn)在可以通過數(shù)據(jù)集訪問了。
為了演示如何訪問數(shù)據(jù)集中的數(shù)據(jù),列表1的printDSData方法在數(shù)據(jù)表中導(dǎo)航,對(duì)于每張表,都顯示列的名稱,緊接著顯示這張表的所有的行。圖3顯示為ReadXmlSchema方法給數(shù)據(jù)集添加的Customer_Id和Order_Id列自動(dòng)生成了值。
請(qǐng)注意,Order.xml出現(xiàn)的三個(gè)元素--PO、Address和Description--沒有映射到數(shù)據(jù)表中。這些數(shù)據(jù)被忽略了,因?yàn)槟闾峁┙o數(shù)據(jù)集的大綱沒有包含這些元素,當(dāng)數(shù)據(jù)集建立關(guān)系數(shù)據(jù)緩存的外形并載入XML數(shù)據(jù)的時(shí)候,它簡(jiǎn)單地忽略了沒有在大綱中描述的數(shù)據(jù)。即使在你從客戶那兒接收到的XML訂單中包含了沒有預(yù)料到的額外數(shù)據(jù),這種簡(jiǎn)便特性也可以讓你的代碼正常地工作。
建立使用數(shù)據(jù)緩存的應(yīng)用程序
現(xiàn)在你已經(jīng)知道如何使用數(shù)據(jù)集為XML數(shù)據(jù)建立關(guān)系數(shù)據(jù)緩存了,你可以應(yīng)用這種技術(shù)來實(shí)現(xiàn)一個(gè)執(zhí)行業(yè)務(wù)邏輯并更新SQL Server的應(yīng)用程序。當(dāng)你使用數(shù)據(jù)集編程模型的時(shí)候?qū)崿F(xiàn)業(yè)務(wù)邏輯相對(duì)直接。ADO.NET為你提供了更新SQL Server中數(shù)據(jù)的幾種選擇,包括使用數(shù)據(jù)適配器、編寫自己的查詢,以及執(zhí)行存儲(chǔ)過程。數(shù)據(jù)集使把XML數(shù)據(jù)映射成關(guān)系模型很容易,剩余的事情是你的了。
相關(guān)文章
MVC微信網(wǎng)頁授權(quán)獲取用戶OpenId
這篇文章主要為大家詳細(xì)介紹了MVC微信網(wǎng)頁授權(quán),在模板頁中獲取用戶openid,感興趣的小伙伴們可以參考一下2016-09-09Asp.net中使用DapperExtensions和反射來實(shí)現(xiàn)一個(gè)通用搜索
這篇文章主要介紹了Asp.net中使用DapperExtensions和反射來實(shí)現(xiàn)一個(gè)通用搜索功能,非常不錯(cuò),具有參考解決價(jià)值,需要的朋友可以參考下2017-03-03ASP.NET Core應(yīng)用錯(cuò)誤處理之StatusCodePagesMiddleware中間件針對(duì)響應(yīng)碼呈現(xiàn)錯(cuò)誤頁面
這篇文章主要給大家介紹了關(guān)于ASP.NET Core應(yīng)用錯(cuò)誤處理之StatusCodePagesMiddleware中間件針對(duì)響應(yīng)碼呈現(xiàn)錯(cuò)誤頁面的相關(guān)資料,需要的朋友可以參考下2019-01-01ASP.NET Core 7 Razor Pages項(xiàng)目發(fā)布到IIS的詳細(xì)過程
這篇文章主要介紹了ASP.NET Core 7 Razor Pages項(xiàng)目發(fā)布到IIS的詳細(xì)過程,詳細(xì)介紹了發(fā)布過程遇到的問題及解決方法,對(duì)ASP.NET Core 發(fā)布到IIS相關(guān)知識(shí)感興趣的朋友一起看看吧2023-01-01ASP.NET單選按鈕控件RadioButton常用屬性和方法介紹
RadioButton又稱單選按鈕,其在工具箱中的圖標(biāo)為 ,單選按鈕通常成組出現(xiàn),用于提供兩個(gè)或多個(gè)互斥選項(xiàng),即在一組單選鈕中只能選擇一個(gè)2014-04-04ASP.NET 運(yùn)行時(shí)錯(cuò)誤: 沒有為擴(kuò)展名“.asax”注冊(cè)的生成提供程序修正版
ASP.NET 運(yùn)行時(shí)錯(cuò)誤: 沒有為擴(kuò)展名“.asax”注冊(cè)的生成提供程序??梢栽?machine.config 或 web.config 中的 <compilation><buildProviders> 節(jié)注冊(cè)一個(gè)。2009-01-01ASP.NET頁面間數(shù)據(jù)傳遞的幾種方法介紹
在ASP.NET中,頁面間數(shù)據(jù)傳遞的方法有很多。下面為大家總結(jié)一下,頁面間數(shù)據(jù)傳遞的方法,來看作者的分析。2013-05-05