本文介紹 visual studio 2005/sql server 2005 環境中用于處理 xml 數據的三個選項,包括使用方案以及指導用戶在各選項之間進行選擇的指南。
一、system.xml、sqlxml 和 xml 數據類型簡介
本節簡要介紹 microsoft sql server 2000 中提供的 xml 支持的發展歷史,并概要介紹 microsoft visual studio 2005/sql server 2005 環境中提供的用于處理 xml 和關系數據的三個選項。這三個選項是:1) system.xml 命名空間中的類,2) sqlxml 類,3) sql server 2005 中提供的 xml 數據類型。
xml 支持最早添加到 microsoft sql server 2000 中,為用戶提供以下功能:
•
將關系數據作為 xml 公開
•
將 xml 文檔拆分到行集合
•
通過使用 xml 數據精簡 (xdr) 方案,將 xml 方案映射到數據庫方案,從而創建 xml 視圖
•
使用 xpath 在 xml 視圖上創建查詢
•
在 sql server 中通過 http 公開數據
此支持在 sqlxml web 的后續版本中得到了進一步增強。增強功能包括:
•
更新程序和 xml 海量加載可以保留對 xml 視圖的更改
•
支持帶批注的 xml 方案定義語言 (xsd),以便描述映射(仍然支持 xdr,但不建議使用)
•
客戶端的 for xml
•
sqlxml 托管類
•
支持 web 服務
microsoft .net framework 1.0 對讀取、寫入和處理 xml 文檔提供了廣泛的支持。這種支持在 .net framework 2.0 中得到了進一步增強,提高了各種 xml 類的性能和可用性。.net framework 在 system.xml 命名空間中提供的新類可用于在 xml 數據與關系數據之間進行相互映射。
sqlxml 是一組使 sql server 數據庫中的關系數據能夠與 xml 無縫集成的庫和技術。它是一個中間層組件,不包括由 for xml 和 openxml 提供的服務器端 xml 支持。sqlxml 提供了一個方案驅動的映射方法,能夠從關系源數據生成 xml 并將表示關系信息的 xml 加載回關系表中。sqlxml 類對 sql server 2000(及更高版本)的數據庫提供了 xml 支持。
microsoft sql server 2005 以 xml 數據類型的形式添加了內置的 xml 支持。xml 數據可以存儲在 xml 數據類型列內部。另外,通過將一個 xml 方案集合與此 xml 數據類型列關聯,還可以對其進行進一步的限制。存儲在 xml 數據類型列中的 xml 值可以借助 xquery 和 xml 數據修改語言 (dml) 進行處理。可以在 xml 數據上建立索引,以增強查詢性能。此外,for xml 和 openxml 也已得到增強,能夠支持新的 xml 數據類型。
sql server 2005 中引入的存儲和處理 xml 數據的新功能與 sql server 早期版本中提供的 xml 功能結合在一起,為開發人員提供了多種在 xml 應用程序中存儲和處理 xml 數據的方法。由于使用 sql server 2005 提供的方法,有多種方法可以生成 xml 應用程序,因此,了解各種不同技術的方案,以及如何在各種技術之間進行權衡和配合對于作出正確的選擇是至關重要的。本文提供了如何選擇適當的方法,使用 sql server 2005 開發 xml 應用程序的指南。
二、xml 使用方案
xml 的應用領域可大致劃分為:
•
用于商業集成的 xml:商業集成,也稱為企業應用集成 (eai),包括 a2a(應用程序對應用程序)、b2b(企業對企業)以及 b2c(企業對用戶)應用程序。運行在不同系統上的應用程序使用基于 xml 的消息相互通訊。
•
用于內容管理的 xml:使用基于 xml 的內容管理系統,用戶可以存儲、檢索、修改和查詢 xml 文檔。這些系統以其原有格式存儲 xml 文檔。
下面介紹符合上述分類的幾種方案。這些方案的解決方案將在以下幾節中給出,并且會詳細介紹 sql server 2005/visual studio 2005 環境中提供的各種 xml 選項的處理情況。
方案 1:保險理賠
一家汽車保險公司在 internet 上提供服務,允許其投保人或代理通過公司的網站進入保險理賠。理賠將由位于公司總部的中央系統進行處理。處理完畢后,系統會將與該理賠相關的信息以指定的 xml 格式存儲起來。系統中必須保留這些 xml 文檔的精確副本,以便用于法律用途。此方案展示了 xml 在內容管理中的應用。
方案 2:汽車制造商與零件供應商之間的數據交換 i
一家汽車制造商與多家零件供應商進行交互,以便獲得公司所需的零件。通常,該制造商要接收供應商的發票。然后,將與發票相關的數據手動輸入到老式的發票處理系統中。發票處理系統以關系格式存儲數據。而現在,該制造商希望將發票數據自動輸入到老式的發票處理系統中。此方案是 xml 用于商業集成的示例。
方案 3:汽車制造商與零件供應商之間的數據交換 ii
此方案包含一家與多家零件供應商進行交互的汽車制造商,如前一方案中所述。該制造商目前使用的系統不能為供應商提供查詢發票狀態或者從制造商獲得付款說明的副本的功能。目前,供應商只能通過電話獲得這些信息。該汽車制造商需要通過 web 公開這些信息,以使供應商能夠自動執行這些任務。此方案展示了 xml 在商業集成中的應用。
方案 4:內容管理系統
某公司通過 web、書籍和 cd-rom 等多種渠道向其客戶提供醫學、法律和技術等領域的信息。該公司要建立一套內容管理系統,以幫助其在較短的時間內向客戶提供高質量的內容。此方案展示了 xml 在內容管理中的應用。
方案 5:客戶調查
某公司在 internet 上提供機票預訂業務,要對每個季節進行調查,以確定當前季節最受客戶喜愛的旅游地點。每個季節所用的調查表均不同,而且將來調查表也可能改變。該公司將對調查信息進行分析,并根據分析結果設計出滿足大多數客戶要求的旅游套餐。此方案可看作 xml 在內容管理中的應用。
三、.net framework 中的 xml 類
microsoft .net framework 對開發基于 xml 的產品提供了卓越的支持。在 .net framework 中,xmltextreader、xmltextwriter、xmldocument 和 xmlvalidatingreader 等核心類可以在 system.xml 命名空間中獲得,該命名空間是所有 xml 類的根命名空間。使用這些核心類,用戶可以使用基于數據流和基于 dom(基于文檔對象模型)的兩種瀏覽/訪問模型來讀取、寫入和驗證 xml 文檔。system.xml 命名空間包含以下子命名空間:
•
system.xml.schema - 包含用于處理 xml 方案定義語言 (xsd) 方案的類。
•
system.xml.serialization - 提供將對象序列化為 xml 格式的文檔或數據流的類。
•
system.xml.xpath - 包括使用 xpath 表達式瀏覽 xml 文檔的類。
•
system.xml.xsl - 具有用于執行可擴展樣式表轉換 (xslt) 的類。
system.xml 命名空間的增強功能
在 visual studio 2005 中,新類(如 xsltcommand)和對現有 xml 類(如 xmldocument)的增強可用于對 xml 數據進行各種操作,包括修改 xml 文檔、應用 xsl 轉換等。
visual studio 2005 中與 system.xml 命名空間中的 xml 類相關的一些增強功能如下:
•
xmldocument 類添加了 xml 方案驗證支持。
•
xmlreader 和 xmlwriter 類的功能得到了增強,性能顯著提高,并支持 xml 方案類型。而且,還添加了靜態 create 方法,提供了一種較為簡單的方法,可使用 xmlreadersettings 和 xmlwritersettings 類創建 xmlreader 和 xmlwriter 實例,以便配置所創建的類型。
有關 system.xml 增強功能的詳細信息,請參見 what's new in system.xml for visual studio 2005 and the .net framework 2.0 release 白皮書。
system.xml 命名空間中的類可用于實現自定義的 xml 分析、處理和存儲邏輯。利用 sql server 2005 的公共語言運行庫 (clr) 的宿主功能以及 visual studio 2005 中的 xml 類,可以在中間層或數據庫層處理 xml。
.net framework 中的 xml 類的使用包括將 xml 文檔作為類型 [n]varchar(max) 或 [n]varbinary(max) 的列保存在數據庫中,或者作為文件保存在文件系統中,以及使用 system.xml 命名空間中的類在中間層或數據庫層處理這些文檔。.net framework 中的 xml 類還可用于操作以 xml 數據類型存儲的數據。
.net framework 中的 xml 類適用于以下情況:
•
訪問 .net framework xml 的所有功能,如數據流分析、文檔類型定義 (dtd)、xsd 驗證、xslt 處理等。
•
僅僅將 sql server 用作 xml 文檔的數據存儲區,不需要在數據庫內部進行深入訪問。
•
使用 .net framework 中的 xml 類進行 xml 文檔的大多數或全部處理并在文檔級進行更新。
可以使用 [n]varchar(max)、[n]varbinary(max) 或 xml 數據類型來存儲 xml。
如果使用 [n]varchar(max) 或 [n]varbinary(max),可以獲得以下好處:
•
可以保留 xml 文檔的高保真的副本,包括空格和格式。
•
應用程序在對整個文檔進行插入和檢索操作方面可以獲得可能實現的最高性能。
后面將介紹使用 xml 數據類型的好處。
在中間層進行 xml 處理
可以使用 .net framework 提供的各種 xml 類在中間層進行 xml 處理。如上所述,采用這種方法時,xml 文檔可以作為類型 [n]varchar(max) 的列或 xml 存儲在數據庫中,也可以作為文件存儲在文件系統中。在中間層,這些文檔是從數據庫中檢索并根據用戶的需要進行處理的,如下所述:
•
如果需要讀取 xml 文檔,可以使用通過 xmlreader.create() 方法創建的 xmlreader 來加載從數據庫中獲得的文檔。使用 read() 瀏覽文檔。xmlreader 類提供對 xml 文檔的最快的只讀、只向前和非緩沖的訪問。
•
如果需要對 xml 文檔進行寫入訪問并需要對 xml 數據進行完全瀏覽訪問,則可以使用 xmldocument 類加載和訪問 xml 文檔。xmldocument 是文檔對象模型 (dom) 在 .net framework 中的一種實現,它是 xml 文檔在內存中的樹型表示,使用它可以瀏覽和編輯此文檔。
•
如果需要根據 dtd/xsd 來驗證 xml 文檔,或者在運行時獲得 xsd 信息,則可以使用 xmlreader 類。在 xmlreadersettings 類上,創建方法時將 xsdvalidation 或 dtdvalidation 設置為 true。還可以設置 validationeventhandle() 事件處理程序來處理讀取過程中出現的驗證錯誤。
•
如果需要對 xml 文檔應用 xsl 轉換,可以使用 xpathdocument 類加載 xml 文檔,然后使用 xslcommand 類應用轉換。xpathdocument 類使用 xslt 為 xml 文檔處理提供了快速的高性能緩存。
•
如果需要使用 xpath 表達式來查詢 xml 文檔,則可以使用 xpathdocument(只讀)或 xmldocument(讀/寫)來加載 xml 文檔。使用 createnavigator() 方法創建一個 xpathnavigator 實例,并將所需的 xpath 表達式作為參數傳遞給 xpathnavigator 的 select() 方法。
在數據庫中進行 xml 處理
sql server 2005 與 clr 的集成使開發人員也能夠使用 .net framework 提供的 xml 類在數據庫層進行處理。這種集成提供了以 .net framework 支持的任何語言編寫存儲過程、函數、觸發器以及用戶定義的類型的功能。此外,clr 宿主還提供了訪問整個 .net framework 基類庫的功能。因此,上一節中介紹的各種 xml 處理選項也可以在數據庫中使用。
使用 clr 集成的優點如下:
•
它提供了使用面向對象語言(如 c# 和 visual basic .net)以托管代碼的形式編寫數據庫對象的能力。
•
托管的數據庫對象比 sql server 早期版本中提供的擴展存儲過程更安全。
•
它具有定義用戶定義的數據類型和用戶定義的合計的能力。
•
在某些情況下,編譯的托管數據庫對象比 transact-sql 具有更高的性能。
在 sql server 2005 中,數據庫開發人員可以選擇兩種方法來編寫存儲過程、觸發器和用戶定義的函數。這兩種方法是 transact-sql 和可在 .net framework 中使用的任何語言,如 c# 或 visual basic .net。語言的選擇取決于對數據執行的操作類型。如果代碼在進行大多數數據訪問時只需要使用很少甚至不使用過程邏輯,選擇 transact-sql 最合適。托管類最適用于數學性較強的函數和過程,如字符串處理、日期操作、系統資源訪問、文件訪問、圖像處理等。
在數據庫層使用 .net framework 中的 xml 類的步驟如下:
•
開發托管程序集。使用可在 .net framework 中使用的任何語言,以程序集的形式實現處理功能,并將程序集打包為 dll。程序集也可以引用其他程序集。
•
注冊程序集并授予權限。使用 .net framework 開發的程序集可以使用 create assembly t-sql 語句注冊到 sql server 中。注冊程序集時,還可以指定要授予該程序集的代碼訪問權限。使用 drop assembly t-sql 語句可以取消程序集的注冊。
•
向 t-sql 公開托管類型。程序集提供的處理功能可以通過用戶定義的標量函數、用戶定義的表函數、用戶定義的過程 (udp) 或者用戶定義的觸發器向 t-sql 公開。用戶定義的標量函數可在任何標量表達式中使用;用戶定義的表函數可在任何 from 子句中使用;udp 可在 exec 語句中調用。
分析方案
保險理賠包含以數據為主的信息(如理賠 id、政策編號、理賠結算數據等)和以文檔為主的信息(如事故損傷說明等)。xml 文檔在匯集以數據為主和以文檔為主的信息時功能非常強大。當前方案的主要要求是需要以 xml 格式保留一份保險理賠的精確副本。使用 sql server,通過將保險理賠作為類型 [n]varchar(max) 或 [n]varbinary(max) 的列存儲在數據庫中的方法,很容易滿足這項要求。值得注意的是,如果需要保留無關緊要的空格、屬性順序、命名空間前綴以及 xml 聲明等信息,則不應使用 xml 數據類型存儲文檔。
優點
使用 [n]varchar(max) 或 [n]varbinary(max) 作為存儲媒介,使用 system.xml 命名空間中的類處理 xml 文檔的優點如下:
•
可以靈活地對 xml 文檔的方案進行更改。在同一列中使用不同的方案存儲 xml 文檔時非常有用。
•
當使用 [n]varchar(max) 或 [n]varbinary(max) 存儲 xml 時,能提供高保真的 xml 文檔。此功能對于處理法律文檔(如保險理賠)的應用程序可能是必不可少的。
•
與將 xml 實例作為文件存儲在文件系統中相比,還可以利用數據庫的功能,如事務更新、并發訪問、備份、復制等。
•
由于這種方法不依賴于數據庫提供的 xml 支持,因此很容易對應用程序進行擴展,以支持多種數據庫服務器,如 sql server、oracle 等。
•
可以使用客戶端系統的處理能力,從而減輕了服務器的負載。通過在中間層進行 cpu 密集的 xml 處理,減輕了服務器的負載,使其能夠用于其他重要的任務。
•
在文檔級進行插入和檢索操作方面提供了可能實現的最佳性能。
•
復雜的操作(如 xsl 轉換)可以作為存儲過程、觸發器或函數在數據庫中完成。
限制
使用 [n]varchar(max) 或 [n]varbinary(max) 進行存儲,使用 system.xml 命名空間中的類處理 xml 實例的限制總結如下:
•
與 xml 數據類型(請參見 sql server 2005 中的 xml 數據類型一節)或 sqlxml 選項(請參見 sqlxml 一節)相比,編碼的復雜性較高。即使數據庫邏輯非常簡單,在中間層或數據庫層用代碼來實現 xml 的分析和處理也很復雜。
•
實現此解決方案的代碼量很大。因此,與 sqlxml 選項相比,維護成本也較高。
•
由于 xml 文檔作為 [n]varchar(max) 存儲在數據庫中,因此不能對 xml 文檔進行深入地更新、插入或刪除操作。查詢能力也有限。
•
以 [n]varchar (max) 數據類型存儲的 xml 文檔最大不能超過 2gb。
•
根據 xml 內容搜索以這種方法存儲的文檔列的代價非常高。
使用 .net framework 中的 xml 類的示例
考慮本文前面介紹的保險理賠方案。一旦理賠獲得批準,保險公司將存儲理賠信息,以便用于法律用途。理賠信息可以作為 [n]varchar(max) 數據類型存儲在數據庫中。
應用程序的流程如下:
1.
處理理賠后,應用程序批準或拒絕理賠。
2.
使用 system.xml 命名空間中的類,為理賠生成 xml 文檔。
3.
將生成的 xml 文檔發送到存儲過程。
4.
存儲過程將 xml 文檔插入到表中。
以下代碼示例使用系統獲得的理賠詳細信息生成一個 xml 文檔并將該 xml 文檔插入到數據庫中。
using system;
using system.xml;
using system.io;
using system.text;
using system.data;
using system.data.sqlclient;
namespace insuranceclaim
{
class insurance
  {
static void main(string[] args)
    {
insurance.insertinsuranceclaim();
    }
static void insertinsuranceclaim()
    {
stringwriter strwriter = null;
xmlwriter writer = null;
 xmlwritersettings settings = null;
sqlconnection connection = null;
sqlcommand command = null;
try
   {
strwriter = new stringwriter();
settings = new xmlwritersettings();
//使用縮進功能以增強可讀性。
settings.indent = true;
settings.encoding = system.text.encoding.utf8;
writer = xmlwriter.create(strwriter, settings);
//編寫 xml 聲明。
writer.writestartdocument();
writer.writestartelement("insuranceclaim");
writer.writestartelement("claiminfo");
writer.writeelementstring("claimid", "c1234");
writer.writeelementstring("claimtype", "3");
writer.writestartelement("settlementdetails");
writer.writestartelement("paymentdetails");
writer.writeelementstring("paidto", "jeff");
writer.writeelementstring("amount", "2000");
writer.writeelementstring("date", "05/12/2002");
writer.writeelementstring("approvedby", "mike");
writer.writeendelement();//paymentdetails 結束
writer.writeendelement();//settlementdetails 結束
writer.writeendelement();//claiminfo 結束
writer.writestartelement("damagereport");
writer.writestring("minor accident occured on ");
writer.writeelementstring("address", "abc street, sample city, sample state");
writer.writestring(" due to ");
writer.writeelementstring("cause", "bad weather");
writer.writestring(" resulted in damage to ");
writer.writeelementstring("damageditem", "head lights");
writer.writeelementstring("damageditem", "engine");
writer.writeendelement();//damagereport 結束
writer.writeendelement();//insuranceclaim 結束
writer.writeenddocument();
//將 xml 寫入文件并關閉寫入程序。
writer.flush();
connection = new sqlconnection();
connection.connectionstring = @"server=localhost;
database=adventureworks;integrated security=sspi;";
command = connection.createcommand();
command.commandtext = "insertinsuranceclaim";
command.commandtype = system.data.commandtype.storedprocedure;
command.parameters.add("@customerid",
system.data.sqldbtype.char);
command.parameters.add("@claim",
system.data.sqldbtype.varchar);
string xml = strwriter.tostring();
string strcustomerid = "1001";
command.parameters[0].value = strcustomerid;
command.parameters[0].size = strcustomerid.length;
command.parameters[1].value = xml;
command.parameters[1].size = xml.length;
connection.open();
command.executenonquery();
connection.close();
    }
finally
    {
if (connection.state == connectionstate.open)
connection.close();
if (writer != null)
writer.close();
if (strwriter != null)
strwriter.close();
    }
  }
  }
}下面是用于創建數據庫表的腳本:
create table [insuranceclaim](
[customerid] [char](4) not null,
[claim] [varchar](max) not null,
[modifieddate] [datetime] not null default (getdate())
)以下存儲過程用于將 xml 文檔插入到數據庫中。
create procedure [dbo].[insertinsuranceclaim]
@customerid [char](4),
@claim [varchar](max)
as
begin
set nocount on;
insert into [insuranceclaim] ( customerid, claim )
values ( @customerid, @claim )
end;四、sqlxml
sqlxml 是與 sql server 2000 一起引入的,它包含在客戶端處理 xml 所需的全部功能。它是一組使 sql server 數據庫中的關系數據能夠與 xml 描述的關系結構數據無縫集成的庫和技術。
在 sql 2000 問世之前,開發人員必須為關系數據與 xml 格式的數據之間的交互提供代碼層。sqlxml 的出現使這種操作變得很簡單,因為它在關系數據與 xml 之間提供了鏈接。本文只討論 sqlxml 托管類。有關該庫其他功能的適用性的詳細信息,請參見 msdn 網站上的 sqlxml 頁。
sqlxml 包含很多在 sql server 中引入的支持 xml 的功能。包括:
•
在客戶端將查詢結果轉換為 xml
•
使用帶批注的 xsd 映射方案文件創建關系數據的 xml 視圖,使您能夠:
•
針對該 xml 視圖定義 xpath 查詢
•
使用被稱為“更新程序”的 xml 模板,對數據庫中的數據進行插入、更新或刪除
•
進行 xml 海量加載操作
•
使用 http 訪問 sql server,使您能夠:
•
在 url 中指定 sql 語句
•
在 url 中指定模板查詢
•
在 url 中指定模板文件
•
在 url 中指定針對帶批注的 xsd 映射方案文件編寫的 xpath 查詢
•
以基于 soap 的 web 服務形式公開存儲過程、用戶定義的函數以及模板查詢所提供的功能。
•
在 .net framework 中編寫代碼,以便利用 sqlxml 通過 sqlxml 托管類所提供的 xml 功能
客戶端 xml 格式化。在客戶端指定 for xml 子句,可以使中間層在由服務器返回的行集合上進行 for xml 轉換,以響應查詢。要在客戶端進行 xml 格式化:
•
如果使用 sqlxml 托管類,則將 sqlxmlcommand 對象的 clientsidexml 屬性設置為 true。
•
如果使用 sqlxmloledb 提供程序,則將 clientsidexml 提供程序特有的屬性設置為 true。
•
如果使用模板查詢,則在模板中指定 client-side-xml="1"。
•
如果使用 http 訪問 sql server,則在 settings(設置)選項卡中的虛擬目錄下選擇 run on the client(在客戶端運行)選項。
•
在客戶端上,for xml 提供的有效 xml 格式化模式為 raw、nested 和 explicit。使用 raw 模式時,所得到的 xml 文檔在查詢結果的每一行中都包含一個 xml 元素,而與行對應的每一列中都包含一個屬性。當指定 nested 模式時,基表名將作為所得到的 xml 文檔的元素名返回。explicit 模式允許在查詢中指定所需的 xml 格式,因此能夠生成任何格式的 xml 文檔。
•
xml 視圖。xml 視圖是使用帶批注的 xsd 方案創建的,該方案定義了關系數據與 xml 數據之間的映射??梢允褂?xpath 查詢對這些 xml 視圖進行查詢。通過 xml 視圖公開的關系數據也可以被修改,然后使用更新程序將所進行的修改提交到數據庫。此外,xml 視圖還可借助基于 com 的 xml bulk load(xml 海量加載)對象將大量 xml 文檔插入到數據庫中。
•
使用 http 訪問 sql server。sqlxml 提供了一個名為“iis 虛擬目錄管理”的工具,該工具可用于設置一個 iis 虛擬目錄,通過 http 公開 sql server 的 xml 功能。借助 sql isapi 擴展的功能,它支持在 url 中直接指定 sql 語句、存儲過程、模板查詢、模板文件以及 xpath 查詢。
•
sqlxml 中的 web 服務支持。sqlxml 3.0 中增加了一項功能,即支持以基于 soap 的 web 服務形式公開 sql server 的功能。此功能使 sql server 能夠從客戶端接收 soap http 請求,以便執行存儲過程、用戶定義的函數和模板。
•
sqlxml 托管類。使用 sqlxml 托管類,可以在 .net framework 中訪問 sqlxml 功能。sqlxml 中有三種托管類:
•
sqlxmlcommand - 處理數據庫連接和查詢執行
•
sqlxmlparameter - 幫助指定查詢中的參數
•
sqlxmladapter - 便于與 .net framework 中的數據集進行交互
使用 sqlxml 托管類,您可以:
•
使用 for xml 子句執行 sql 查詢
•
針對映射方案執行 xpath 查詢
•
執行模板查詢
•
執行模板查詢文件
•
執行更新程序
•
執行區分程序
使用 sqlxml 將關系數據作為 xml 文檔公開非常適用于以下情況:
•
應用程序接收結構良好且能較好地映射到關系表中的 xml 數據。
•
應用程序必須將來自外部應用程序的大量 xml 文檔加載到數據庫中,并保持其關系格式。
•
應用程序不需要保留文檔的順序。
•
應用程序需要以不同的格式向多個數據使用者提供相同的數據。
•
dml 操作的性能對于應用程序至關重要。
•
應用程序需要充分利用優化程序進行查詢優化。
•
應用程序需要進行深入的數據操作。
•
應用程序需要以 xml 的形式公開現有的關系數據。
分析方案
在 xml 使用方案中介紹的第一個數據交換方案(請參見方案 2:汽車制造商與零件供應商之間的數據交換 i 一節),一個汽車制造商與多個零件供應商之間的交互是使用 sqlxml 的典型案例。制造商必須與不同的供應商進行通訊以便交換發票數據。建議的解決方案使用 web 服務和 sqlxml 來解決此問題。制造商公開一個 web 服務,供應商可使用該服務將發票發送給制造商。web 服務使用了一個針對客戶的 xslt,將發票由供應商的格式轉換為制造商使用的通用格式。然后,web 服務使用 xml 視圖來分解 xml 文檔,將發票文檔的內容映射到關系表中的列。老式的發票處理系統將能夠從關系表中選取數據并進行處理。在此方案中使用 xml 視圖的優點如下:
•
降低了維護成本。通過修改針對供應商的 xslt 文件,很容易適應供應商對發票方案所進行的任何更改。
•
與 for xml 相比,編碼的復雜程度降低了(請參見關系/xml 集成的服務器端支持 (for xml/openxml) 一節)。
•
通過創建針對供應商的 xslt 文件,很容易支持新的供應商。
優點
使用 sqlxml 的優點總結如下:
•
與服務器端的 for xml explicit 相比,創建帶批注的映射方案將關系數據映射到 xml 數據是一種相對簡單、易于維護的解決方案。
•
sqlxml 能夠創建可更新的雙向 xml 視圖,而使用 for xml 只能創建關系數據的只讀 xml 表示形式。
•
映射 xsd 便于適應 xml 格式的更改請求,而不必進行主代碼的更改。這會使維護簡單易行。
•
sqlxml 允許用戶通過將 sqlxmlcommand 類的 clientsidexml 屬性設置為 true,在客戶端進行 xml 格式化,從而減輕服務器的負載。
限制
從不利的方面來看,從客戶端使用 sqlxml 有一些限制:
•
xml 視圖不適用于 xml 文檔的層次結構過多或者遞歸深度未知的情況。
•
sqlxml 不適用于包含混合內容標記和有序數據的說明性文檔,例如產品目錄、新聞報告等。
•
由于不能保留文檔順序,很難重新構造出原始的 xml 文檔。
•
雖然將 xml 文檔分解到關系表中提供了卓越的搜索性能,但是在關系數據與 xml 之間進行相互轉換的代價非常昂貴。
•
當在 xsd 映射方案中使用默認映射時,可能會公開數據庫表名和列信息,這可能無意中造成信息泄漏。這種風險可以通過為表和列指定明確的映射加以避免。
•
url 中的 sql 語句只能用于可信的局域網中。在 internet 上使用這種查詢可能導致潛在的安全問題。
使用 sqlxml 的示例
以上概要介紹了 sqlxml 的功能,下面將詳細分析一個可以應用 sqlxml 托管類的示例??紤]一個簡單的示例 - 為特定客戶導出銷售訂單的詳細信息。該示例所用的表可以在 adventureworks 數據庫中獲得。
數據庫中的數據必須能夠在客戶端以 xml 格式獲得,并能被表示層顯示。下面您將看到,如何使用 sqlxml 類將 sql 數據庫中的關系數據作為 xml 數據進行處理。該示例使用映射 xml 方案進行處理,并將 xml 節點名映射到表字段。有關使用 sqlxml 托管庫處理關系數據的詳細信息,請參見 msdn 網站上的sqlxml頁。
以下帶批注的 xsd 方案定義了關系表 [sales.customer]、[sales.salesorderheader] 和 [sales.salesorderdetail] 與客戶銷售訂單詳細信息的目標 xml 表示之間的映射。還可以使用 xsd 映射方案來定義 xml 中的父子關系,如以下 xsd 方案所示。
<xsd:schema xmlns:xsd="http://www.w3.org/2001/xmlschema"
xmlns:sql="urn:schemas-microsoft-com:mapping-schema">
<xsd:annotation>
<xsd:appinfo>
<sql:relationship name="customerorderheader"
parent="sales.customer"
parent-key="customerid"
child="sales.salesorderheader"
child-key="customerid" />
<sql:relationship name="orderheaderorderdetail"
parent="sales.salesorderheader"
parent-key="salesorderid"
child="sales.salesorderdetail"
child-key="salesorderid" />
</xsd:appinfo>
</xsd:annotation>
<xsd:element name="customer" sql:relation="sales.customer" >
<xsd:complextype>
<xsd:sequence>
<xsd:element name="order" sql:relation="sales.salesorderheader" 
sql:relationship="customerorderheader" maxoccurs="unbounded" >
<xsd:complextype>
<xsd:sequence>
<xsd:element name="orderdetail"
sql:relation="sales.salesorderdetail"
sql:relationship="orderheaderorderdetail"
maxoccurs="unbounded" >
<xsd:complextype>
<xsd:attribute name="salesorderid"
type="xsd:integer" />
<xsd:attribute name="productid" type="xsd:integer" />
<xsd:attribute name="orderqty" type="xsd:integer" />
</xsd:complextype>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="salesorderid" type="xsd:integer" />
<xsd:attribute name="customerid" type="xsd:integer" />
<xsd:attribute name="orderdate" type="xsd:date" />
<xsd:attribute name="shipdate" type="xsd:date" />
</xsd:complextype>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="customerid" type="xsd:integer" />
</xsd:complextype>
</xsd:element>
</xsd:schema>
class exportorders
{
/// <摘要>
///  此方法使用 sqlxmlcommand 類從
///  sales.customer、sales.salesorderheader 和 sales.salesorderdetail
///  表中選擇記錄。數據是從服務器獲取并在客戶端
///  格式化為 xml 的。請注意,clientsidexml 設置為 true。
/// <摘要>
static void main(string[] args)
{
if (args.length < 1)
  {
console.writeline("usage");
console.writeline("customerorders <customerid> [orderid]");
return;
  }
try
  {
stringbuilder strbuilder = new stringbuilder();
strbuilder.append("/customer[@customerid='");
strbuilder.append(args[0]);
strbuilder.append("']");
if (args.length > 1)
   {
strbuilder.append("/order[@salesorderid='");
strbuilder.append(args[1]);
strbuilder.append("']");
   }
sqlxmlcommand xmlcommand = new sqlxmlcommand(@"provider=
sqloledb; server=localhost; database=adventureworks;
integrated security=sspi;");
xmlcommand.clientsidexml  = true;
xmlcommand.roottag   = "customerorders";
xmlcommand.schemapath   = @"customerorderdetails.xsd";
xmlcommand.commandtype   = sqlxmlcommandtype.xpath;
xmlcommand.commandtext   = strbuilder.tostring();
stream reader     = xmlcommand.executestream( );
filestream fsout = file.create("customerorder.xml");
streamwriter sw = new streamwriter(fsout);
using (streamreader sr = new streamreader(reader))
   {
sw.write(sr.readtoend());
   }
sw.flush();
sw.close();
fsout.close();
  }
catch (exception exception)
  {
console.writeline( exception.tostring() );
  }
}
}上述方法為作為應用程序命令行參數指定的客戶 id 導出了銷售訂單的詳細信息。數據在客戶端轉換為 xml 格式,從而避免了服務器端的性能問題。請注意,上述帶批注的 xsd 方案映射必須保存為 customerorderdetails.xsd,才能使上述代碼片段正常運行。
注意:從此示例中可以看出,用于從數據庫中檢索 xml 數據的代碼非常少。
五、關系/xml 集成的服務器端支持 (for xml/openxml)
sql server 通過 select 語句的 for xml 擴展功能,支持在服務器端以 xml 文檔的形式返回 sql 查詢結果。另外,關鍵字 openxml 還能夠提供從 xml 文檔中提取行集合的能力。
for xml
服務器端的 for xml 支持四種 xml 轉換模式 - raw、auto、explicit 和 path。
默認情況下,raw 模式將查詢結果集中的每一行映射到一個 xml 元素,并將行中的每一列映射到一個屬性。當使用 row 模式指定 elements 選項時,行中的每一列將被映射到為該行生成的元素的子元素中。還可以通過指定 xmlschema 選項為所生成的 xml 請求一個內聯方案。
auto 模式支持生成嵌套的 xml 元素,默認情況下,from 子句中的每個表(在 select 子句中至少列出一列)將映射到一個 xml 元素,select 子句中的列將映射到屬性(如果指定 elements 選項,則映射到子元素)。
explicit 模式能夠最大限度地控制由查詢結果生成的 xml 的格式。使用它,您可以通過在查詢中指定所需的 xml 格式來生成任何格式的 xml。
使用 explict 模式編寫復雜的 xml 文檔是相當繁瑣的。如果不想編寫復雜的 explicit 模式請求,還可以使用 path 模式,該模式還具有編寫嵌套 for xml 查詢和 type 指令以返回 xml 類型實例的能力。path 模式通過將列名解釋為類似 xpath 的語法,將 select 查詢返回的行集合中的列映射到屬性和子元素。有關 sql server 2005 中 for xml 增強功能的詳細信息,請參見 what's new in for xml in microsoft sql server 2005 白皮書。
openxml
openxml 與 sp_xml_preparedocument 和 sp_xml_removedocument 系統存儲過程共同提供了 xml 文檔的關系行集合視圖。為了對 xml 文檔使用 openxml,必須使用 sp_xml_preparedocument 創建 xml 文檔的一個內存中表示。此存儲過程使用 msxml 分析器分析 xml 文檔,并向 xml 文檔返回一個可用于 openxml 的句柄?,F在,xml 文檔句柄、行模式(將 xml 數據的節點映射到行的 xpath 表達式)、行集合方案以及行集合列與 xml 節點之間的映射等參數都可以傳遞到 openxml 以獲得行集合。當不再需要 xml 文檔時,必須使用 sp_xml_removedocument 存儲過程將其從內存中卸載。
for xml 的增強功能
在 sql server 2005 中,for xml 增強了以下功能:
•
使用新的 type 指令轉換 for xml 結果的類型
•
將 for xml 的結果分配給各種類型的 xml
•
對 for xml 查詢進行嵌套處理,以生成 xml 層次結構
•
使用新的 path 模式生成復雜的 xml 文檔
•
使用 xmldata 和 xmlschema 選項分別生成 xdr 或 xsd 格式的內聯方案
•
在 raw 模式下使用 elements 指令生成以元素為主的 xml
•
在 element 指令中使用 xsinil 選項,將 null 值映射到屬性為 xsi:nil="true" 的元素
openxml 的增強功能
在 sql server 2005 中,openxml 的功能得到了增強,支持以下功能:
•
將 xml 類型數據傳遞到 sp_xml_preparedocument
•
在 with 子句中使用新數據類型
使用 for xml 和 openxml 編寫和分解 xml 文檔非常適用于以下情況:
•
應用程序需要按照一定的關系存儲數據,并將此信息以 xml 的形式公開給另一個應用程序。
•
應用程序不需要保留 xml 的順序。
•
應用程序要執行大量元素級 dml 操作。
•
應用程序需要進行深入的數據訪問和更新。
•
應用程序需要通過 web 服務公開關系數據。
分析方案
方案 3 中的要求(請參見方案 3:汽車制造商與零件供應商之間的數據交換 ii 一節)是提供一種 web 服務,使供應商可以使用該服務獲得發票的狀態或者獲得付款說明的副本。for xml 與 web 服務結合,提供了一種解決方案,允許制造商在 internet 上公開這些服務。供應商可以使用 web 服務查詢其發票的狀態。然后,web 服務將使用供應商提供的發票 id,并使用 for xml 語句從關系數據中生成 xml 格式的響應。生成的 xml 文檔將返回給供應商。在當前方案中,使用基于 for xml 語句的方法具有以下優點:
•
for xml 提供了一種從關系數據中動態編寫簡單 xml 文檔的簡單方法。
•
當用于編寫簡單的 xml 文檔時,for xml 查詢較 xml 視圖更易于維護。
優點
使用 for xml/openxml 的優點如下:
•
for xml 提供了一種在服務器上從關系數據生成 xml 的簡單方法。
•
for xml 提供了通過 web 服務公開商業信息的能力。
•
使用 openxml,可以將行集合以 xml 格式傳遞給存儲過程,這將使您能夠在一個網絡往返中進行大量的 insert、update 和 delete 操作。
•
for xml 與 xsl 結合,可用于應用程序集成或商業集成。
限制
使用 for xml/openxml 編寫和分解 xml 文檔的限制如下:
•
使用 for xml 的 explict 選項構造 xml 的結構非常困難。
•
很難維護使用 for xml explicit 編寫的復雜查詢。
•
由 for xml auto 生成的 xml 文檔可能會公開數據庫表名和列信息,導致無意中泄漏信息。這種情況可以通過為表和列指定別名加以避免。
使用 for xml 和 openxml 的示例
以下示例使用 sql server 2005 附帶的 adventureworks 數據庫。此示例使用 for xml 為指定范圍內的客戶從 [sales.customer]、[sales.salesorderheader]、[production.product] 和 [sales.salesorderdetail] 表中獲得客戶、訂單以及訂單詳細信息等信息。
示例:使用 for xml
select cust.customerid,
orderheader.customerid,
orderheader.salesorderid,
detail.salesorderid, detail.linenumber,detail.productid,
product.name,
detail.orderqty
from sales.customer cust,
sales.salesorderheader orderheader,
sales.salesorderdetail detail,
production.product product
where cust.customerid = orderheader.customerid
and  orderheader.salesorderid = detail.salesorderid
and  detail.productid = product.productid
and  (cust.customerid between 44 and 46)
order by orderheader.customerid,
orderheader.salesorderid
for xml auto查詢結果如下:
<cust customerid="44">
<orderheader customerid="44" salesorderid="53575">
<detail salesorderid="53575" linenumber="2" productid="952" orderqty="2">
<product name="chain" />
</detail>
<detail salesorderid="53575" linenumber="1" productid="969" orderqty="1">
<product name="touring-1000 blue, 60" />
</detail>
<detail salesorderid="53575" linenumber="3" productid="972" orderqty="1">
<product name="touring-2000 blue, 54" />
</detail>
</orderheader>
<orderheader customerid="44" salesorderid="59024">
<detail salesorderid="59024" linenumber="1" productid="972" orderqty="3">
<product name="touring-2000 blue, 54" />
</detail>
<detail salesorderid="59024" linenumber="2" productid="957" orderqty="2">
<product name="touring-1000 yellow, 60" />
</detail>
</orderheader>
</cust>
<cust customerid="46">
<orderheader customerid="46" salesorderid="48354">
<detail salesorderid="48354" linenumber="1" productid="730" orderqty="1">
<product name="ll road frame - red, 62" />
</detail>
</orderheader>
</cust>以下示例使用 openxml 和 xpath 表達式提取 xml 文檔中指定的訂單詳細信息。
示例:使用 openxml
declare @xmldocumenthandle int
declare @xmldocument nvarchar(max)
set @xmldocument = n'<root>
<cust customerid="44">
<orderheader customerid="44" salesorderid="53575">
<detail salesorderid="53575" linenumber="2" productid="952" orderqty="2">
<product name="chain" />
</detail>
<detail salesorderid="53575" linenumber="1" productid="969" orderqty="1">
<product name="touring-1000 blue, 60" />
</detail>
<detail salesorderid="53575" linenumber="3" productid="972" orderqty="1">
<product name="touring-2000 blue, 54" />
</detail>
</orderheader>
<orderheader customerid="44" salesorderid="59024">
<detail salesorderid="59024" linenumber="1" productid="972" orderqty="3">
<product name="touring-2000 blue, 54" />
</detail>
<detail salesorderid="59024" linenumber="2" productid="957" orderqty="2">
<product name="touring-1000 yellow, 60" />
</detail>
</orderheader>
</cust>
<cust customerid="46">
<orderheader customerid="46" salesorderid="48354">
<detail salesorderid="48354" linenumber="1" productid="730" orderqty="1">
<product name="ll road frame - red, 62" />
</detail>
</orderheader>
</cust>
</root>'-- 創建 xml 文檔的內部表示。
exec sp_xml_preparedocument @xmldocumenthandle output, @xmldocument
-- 使用 openxml 行集合提供程序執行 select 語句。
select *
from openxml (@xmldocumenthandle, '/root/cust/orderheader/detail',2)
with (customerid varchar(10) '../@customerid',
orderid   int     '../@salesorderid',
linenumber int     '@linenumber',
productid  int     '@productid',
quantity  int     '@orderqty')-- 刪除內部表示。
exec sp_xml_removedocument @xmldocumenthandle查詢結果如下:
--------------------------------------------------------
customerid  orderid  linenumber  productid  quantity
--------------------------------------------------------
44   53575   2   952   2
44   53575   1   969   1
44   53575   3   972   1
44   59024   1   972   3
44   59024   2   957   2
46   48354   1   730   1
--------------------------------------------------------六、sql server 2005 中的 xml 數據類型
xml 數據的層次結構特性使其很難被建模成關系數據,因為這會使數據結構變得非常復雜(如層次的深度將增加等)。而且,當 xml 數據映射到關系數據時,也無法保留 xml 實例中的元素順序,因此從分解得到的關系數據編寫原始的 xml 文檔代價相當高。由于關系模型對存儲 xml 數據有諸多限制,因此在內部存儲 xml 實例是一種較理想的方法。內部 xml 實例不會受關系模型的限制,并能提供多種功能,例如能夠處理層次結構或嵌套數據、能夠保留元素順序、能夠直接存儲和檢索 xml 數據以及能夠靈活地支持多種方案等。
microsoft sql server 2005 為 xml 數據處理提供了廣泛支持。使用 sql server 2005,xml 值可存儲在內部的 xml 數據類型列中,可以根據 xml 方案的集合設置其類型,也可以不設置類型。還可以通過 xquery 和 xml dml 支持深入的數據處理,后者是針對數據修改的擴展。此外,還可以為 xml 列創建索引,以提高查詢性能。
有類型的 xml
有類型的 xml 非常適用于擁有描述 xml 數據的 xml 方案的情況。在這些情況下,可以將 xml 方案的集合與 xml 列關聯,以生成有類型的 xml。對 xml 類型列的驗證是根據與該列關聯的 xml 方案集合進行的。另外,包含有類型的 xml 數據的查詢比包含無類型的 xml 數據的查詢的性能要好,因為它不需要在運行時轉換節點值。
無類型的 xml
無類型的 xml 適用于有方案但不想讓服務器驗證數據的情況,或者沒有方案的情況。在下列情況下,即使有方案,可能也要存儲無類型的 xml:
•
沒有固定的方案
•
在服務器端存儲數據之前,已在客戶端進行驗證
•
臨時存儲根據方案確定無效的 xml 數據
•
使用服務器端不支持的方案組件(如 key/keyref)
即使無類型的 xml 文檔不與任何方案關聯,系統仍要對其進行檢查,以確保其格式良好。值得注意的是,由于無類型的 xml 需要在運行時轉換節點值,其性能會受到一定的影響,因為節點值是作為 unicode 字符串內部存儲的。
xml 數據類型的使用方案
使用 sql server 2005 中的新 xml 數據類型,可以實現以下功能:
•
創建既包含關系列,又包含有 xml 類型列的表。
•
通過與 xml 方案集合關聯,創建有類型的 xml 列類型。
•
對涉及其他 xml 或非 xml 類型列的 xml 列進行限制,以強制實現業務規則。
•
創建可用于存儲 xml 數據類型實例的 xml 類型的變量。
•
為存儲過程或用戶定義的函數創建 xml 類型的參數。
•
從用戶定義的函數中返回 xml 類型值。
•
將使用新的 type 指令獲得的 for xml 查詢結果分配給 xml 類型的變量。
•
運行 xquery 子集,在 xml 結構內查詢并轉換 xml 數據。
•
根據 xml 類型的列創建計算列。
•
為 xml 類型的列創建 xml 索引,以提高查詢性能。
•
使用 xml dml 對 xml 實例進行元素級的插入、刪除和更新操作。
•
將 xml 類型數據的實例傳遞到 sp_xml_preparedocument,以準備 xml 文檔的內存中表示。
•
使用 xquery 和 xml dml 編寫包含關系和 xml 列的跨域查詢。
•
使用 cast 和 convert,分別將 xml 類型轉換為 varchar 或 nvarchar 類型。
•
使用 cast 或 convert,將字符串數據類型(如 [n]varchar、[n]text、varbinary 和 image)轉換為 xml 類型。
xml 數據類型方法和 xml dml
可以通過五種方法對 xml 數據類型列進行查詢和處理。使用 xml 數據類型的 query() 方法,可以提取 xml 文檔的片段;query() 方法接受 xquery 表達式作為參數,并返回無類型的 xml 實例;使用 value() 方法,通過指定 xquery 表達式以及需要返回的 sql 類型,可以從 xml 實例中提取標量值;使用 exist() 方法,可以檢查 xml 實例是否存在;使用 nodes() 方法,可以方便地將 xml 文檔分解為關系數據。
使用 modify() 方法,可以對 xml 實例進行數據處理。通過 xquery 中添加的 insert、delete 和 update 關鍵字提供了對 xml dml 的支持。使用 insert、delete 和 update 關鍵字可以分別插入、刪除和更新一個或多個節點。
xml 索引
如果 xml 實例非常大,那么在對 xml 數據類型列執行查詢處理操作時所進行的分析和分解可能要持續相當長的時間。在這些列上創建索引將提高對 xml 數據類型的查詢性能。xml 數據的大小和使用方案對確定所需的索引類型非常重要。sql server 支持兩種類型的索引 - 主 xml 索引和次 xml 索引;沒有前者,后者就不能存在。
在 xml 列上創建主 xml 索引,將分解 xml blob 并將這些值存儲在一個內部表中。這樣,由于運行時不必進行分解,就可以提高運行時的查詢性能。根據使用方案的不同,還可以創建次 xml 索引,進一步提高查詢性能??梢詣摻ㄈN類型的次 xml 索引 - path、property 和 value,分別提高路徑、屬性和值的查詢性能。有關為 xml 類型列選擇適當的次索引的方法,請參見“performance optimizations for the xml data type”白皮書。
將 xml 文檔存儲為 xml 數據類型非常適用于以下情況:
•
應用程序需要保留 xml 實例的信息集內容。xml 文檔的信息集內容包括文檔層次結構、元素順序、元素值及屬性等。應用程序不保留屬性順序、命名空間前綴、無關緊要的空格以及 xml 聲明等信息。
•
應用程序需要對 xml 文檔進行元素級的修改和查詢操作。
•
應用程序需要 xml 數據類型列的索引,以加快查詢處理。
•
xml 數據不一定有方案。
•
應用程序使用各種結構的 xml 文檔,或者 xml 文檔要符合難以映射到關系結構的各種不同或復雜方案。
分析方案
分析方案:內容管理系統
現在,讓我們來分析一下 xml 使用方案中介紹的內容管理系統。出版公司要處理文本、圖像、音頻、視頻等各種形式的信息。可獨立使用的信息塊是從各種來源收集并在數據庫中進行維護的。這些信息塊被稱為“組件”。將各個組件組裝起來即可創建文檔。文檔中要包括哪些組件取決于用戶的需要。這些文檔將通過各種渠道發送給預訂的用戶。內容管理系統通常需要具有高性能、高可縮放性地存儲、檢索、搜索和更新內容的能力。
xml 作為一種統一標準的數據模型提供了一種極好的方法,可以在同一個文檔中同時存儲 xml 數據和 xml 內容。xml 還具有將顯示方式與數據本身隔離的能力,這一點非常重要,因為相同的信息用于不同用戶的顯示方式可能不同。sql server 2005 提供的內置 xml 數據類型可以滿足這種內容管理系統的需要。通過 xml 數據類型,可以存儲 xml 文檔,使用 xml dml 在元素級修改 xml 文檔,以及使用 xquery 對 xml 文檔進行查詢。
分析方案:客戶調查
在客戶調查 xml 使用方案中,主要要求是存儲具有多種方案的調查信息。不能使用一個關系表為沒有固定方案的數據建模。包含 xml 列的關系表是存儲此類信息的最佳選擇。還可以為關系表另外添加一列,用于存儲調查類型。通過使用調查類型列提取該調查類型的所有記錄,可以對與某種類型調查相關的信息進行分析。在一般的調查中,用戶通常不會回答所有問題。因此,與其創建多個列(每列對應調查中的一個問題)并在數據庫中為未回答的問題存儲 null 值,倒不如將每個客戶的調查信息作為 xml 文檔存儲在一列中。將客戶的調查信息作為 xml 類型列存儲更適合此方案,因為:
•
使用 xml 類型列,不同方案的調查信息可以存儲在一個 xml 類型列中。將 xml 類型列與 xml 方案集合關聯,這樣用戶就可以為多個調查類型存儲數據。
•
調查信息可以在用戶界面上進行驗證,而不必將此信息作為有類型的 xml 數據類型列進行存儲,從而實現數據庫級的驗證。
•
xquery 可用于執行數據分析。
優點
在 xml 數據類型列中存儲 xml 數據的優點總結如下:
•
xml 數據類型提供了一種在服務器上存儲 xml 數據的簡單直觀的方法,同時還保留了文檔順序和文檔結構。這一點特別適用于文檔順序和文檔結構非常重要的文檔。假定一個簡單的方案:應用程序從某個數據源獲得了一個 xml 文檔,并且要存儲該文檔。將其存儲在 nvarchar 或 text 列都不能保證 xml 的格式良好,而且不能輕易訪問其內容。在這種情況下,最好將傳入的 xml 文檔存儲在內部的 xml 列中。
•
xml 數據類型能夠對 xml 數據進行深入的查詢和修改操作。在 sql server 2005 之前,沒有辦法在數據庫內部存儲 xml。因此,如果要修改或查詢 xml 數據,必須從 nvarchar 或 text 列中加載數據,由字符串創建 xml 文檔,然后才能進行修改。將修改過的數據寫回數據庫的步驟與此類似。而現在使用 xml 數據類型,這些步驟就變得非常簡單。
•
使用 xml 數據類型,可以為 xml 數據類型列創建索引,從而加快查詢處理。
•
使用 xml 數據類型時,可以對 xml 數據使用 xml 方案集合和限制,從而強制實現業務規則。xml 方案可用于驗證數據,添加基于類型的操作語義,在編寫查詢和數據修改語句過程中進行比無類型的 xml 更精確的類型檢查,并且可以優化存儲和查詢處理。
•
由于 xml 類型的數據存儲在數據庫中,因此它還具有很多數據庫的功能,如備份和恢復、sql server 安全性、事務、日志等。
限制
以下是使用新的 xml 數據類型時必須了解的一些限制:
•
不能存儲精確的數據副本。不能保留無關緊要的空格、命名空間前綴、屬性順序和 xml 聲明。
•
xml 文檔的層次最多為 128 層。
•
xml 文檔的內部二進制表示最大為 2gb。
•
xml 實例不能進行比較。因此:
•
xml 列不能成為主鍵約束或外鍵約束的一部分。
•
xml 列不能作為分組值在 group by 語句中使用。
•
xml 不能轉換為 text、ntext 和 image 數據類型,因為在 sql server 2005 中不能使用這些類型。但是,xml 數據類型可以轉換為 [n]varchar 和 [n]varbinary 類型。
使用 xml 數據類型的示例
示例應用程序使用 adventureworks 數據庫中的 sales.store 表。sales.store 表包含 customerid 作為主鍵,包含 demographics 作為 xml 列。demographics 列包含存儲調查信息。存儲調查中存儲的信息是可選的。這意味著,demographics 列不一定包含所有元素。如果相同的信息已存儲為關系格式,則需要將這些元素創建為表的列。由于大多數存儲調查信息是可選的,因此對于大多數數據,這些列中將包含 null 值。這將導致表空間的浪費。為了避免這種浪費,將 demographics 列中的存儲調查信息存儲為 xml 格式。demographics 列包含每個客戶的銷售信息,即年銷售額、年收入及銀行名稱等。這些字段作為 xml 元素存儲在數據中。
示例應用程序具有以下功能:
•
顯示所有客戶及其調查信息的列表。
•
顯示特定客戶的調查信息。
•
向 sales.store 表中插入新客戶及其調查信息。
•
修改給定客戶的調查信息的某些元素(如年銷售額、年收入等)。
•
刪除給定客戶的調查信息。
應用程序使用 system.data.sqltypes.sqlxml 類從 xml 列中檢索數據。sqlxml 類是對 xml 列的直接映射。
使用 sqlxml 類,可以直接從 xml 列檢索數據,而不需要任何映射或轉換。
下面,讓我們看一個如何為客戶 id 12 檢索年收入元素的示例。以下代碼示例展示了上述的第二種功能。
public void retreiveannualrevenue ()
{
sqlconnection conn = new sqlconnection();
conn.connectionstring = @"server=localhost; database=adventureworks;
integrated security=sspi";
conn.open();
sqlcommand command = conn.createcommand();
command.commandtext = @"select demographics.query(
'declare namespace ss="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/storesurvey"
<storeinfo>
  <annualrevenue>
{data(/ss:storesurvey/ss:annualrevenue)}
</annualrevenue>
</storeinfo>') as
result from sales.store where customerid=12";
sqldatareader datareader = command.executereader();
system.text.stringbuilder builder = new system.text.stringbuilder();
while (datareader.read())
  {
sqlxml sqlxml = datareader.getsqlxml(0);
builder.append(sqlxml.value);
  }
//注意:xml1 是一個 xml web 控件
this.xml1.documentcontent = builder.tostring();
this.xml1.transformsource = @"storeinfo.xslt";
}上述方法在 adventureworks 數據庫中創建了一個 sqlconnection 對象實例。命令文本屬性包含為客戶 id 12 檢索年收入字段值的查詢。
這是一個 xquery,將在 xml 列上直接執行。查詢的返回值將是一個 xml 片段,該片段將映射到 sqlxml 類。然后,可以使用 sqlxml 類的 value 屬性檢索該 xml 片段。
檢索到的 xml 片段將使用 xml web 服務器控件顯示在客戶端應用程序中。
七、不同方法的比較
| 功能 | .net framework 中的 xml 類 | for xml / openxml | sqlxml | xml 數據類型 | 
| 代碼的復雜性 | 高。沒有類可以在 xml 數據和關系數據之間直接進行映射。 | 中。使用 for xml explicit 編寫查詢非常困難。 | 低。sqlxml 類提供了一種將關系數據作為 xml 數據進行處理的機制,而且更新程序還可以方便地更新記錄。 | 低。由于 xml 數據同樣也存儲在列中,因此復雜性很低。另外,visual studio 2005 還提供了處理 xml 數據類型的類。xml dml 可用于修改 xml 數據。 | 
| 可維護性 | 復雜。對表中字段或 xml 的更改需要更改代碼。 | 困難。對表中字段或 xml 的更改需要更改查詢。 | 容易。在大多數情況下,修改映射 xsd 文件即可適應更改。 | 容易。xquery 提供了在數據庫中查詢 xml 列的簡單語法。 | 
| 安裝 | 除 .net framework 外,不需要進行其他安裝。 | 不需要進行其他安裝。 | 需要在客戶端計算機上安裝 sqlxml 庫。 | 不需要進行其他安裝。 | 
| 安全性 | 在很大程度上是安全的,因為通常情況下,數據類型和格式不會在客戶端公開。 | 如果適當注意避免泄漏表名和列名,則是安全的。 | 如果映射 xsd 文件存儲在客戶端而不是在中間層,則在設計時應考慮安全因素。 | 安全 | 
| 支持 .net compact framework | 有限的支持。microsoft .net compact framework 不支持 xmldatadocument。 | 支持 | 不支持 | 不支持。如果 sql server 中的 xml 數據類型列與 sql server mobile 同步,則它將轉換為 ntext。 | 
| 數據驗證 | 可由客戶端和服務器實施。 | 可由服務器實施。 | 可由客戶端實施。 | 可由服務器使用 xml 方案實施。 | 
| 數據存儲 | [n]varchar(max)、xml 或 [n]varbinary(max) | 關系表(可將 xml 作為字段使用)。 | 關系表(可將 xml 作為字段使用)。 | xml 數據類型 | 
| 保真度 | 高保真(保留字節級的 xml 數據) | 關系保真(保留數據的層次結構,但忽略元素的順序) | 關系保真 | 信息集保真(保留 xml 數據的信息集內容) | 
| 存儲數據的訪問和更新 | 支持文檔級更新。 | 支持深入的數據訪問和更新。 | 支持深入的數據訪問和更新。 | 支持深入的數據訪問和更新。 | 
結論
本文為用戶提供了在 sql server 2005 中處理 xml 的各種選項,并對 system.xml 命名空間、sqlxml 和 xml 數據類型進行了討論,介紹了其相關的優點和局限性,并給出了示例方案。根據本文介紹的理想方案的性能,用戶可以為自己的應用程序選擇適當的 xml 選項。
新聞熱點
疑難解答