Enterprise Library 4 数据访问应用程序块
?
Enterprise Library 數(shù)據(jù)訪問(wèn)應(yīng)用程序塊簡(jiǎn)化了實(shí)現(xiàn)常規(guī)數(shù)據(jù)訪問(wèn)功能的開發(fā)任務(wù)。應(yīng)用程序可以在各種場(chǎng)景中使用此應(yīng)用程序塊,例如為顯示而讀取數(shù)據(jù)、傳遞數(shù)據(jù)穿過(guò)應(yīng)用程序?qū)? application layers)、以及將修改的數(shù)據(jù)提交回?cái)?shù)據(jù)庫(kù)系統(tǒng)。應(yīng)用程序塊包含對(duì)存儲(chǔ)過(guò)程和內(nèi)聯(lián) SQL 的支持。常規(guī)內(nèi)部(housekeep)處理,如管理連接、創(chuàng)建并緩存參數(shù),都封裝在應(yīng)用程序塊的方法中。換句話說(shuō),數(shù)據(jù)訪問(wèn)應(yīng)用程序塊在簡(jiǎn)單易用的類中提供了對(duì) ADO.NET 的最常用的特性的訪問(wèn);這提高了開發(fā)人員的工作效率。
ADO.NET 2.0 提供了如 DbCommand 類和 DbConnection 這樣的類,這些類有助于從任何特定數(shù)據(jù)庫(kù)實(shí)現(xiàn)中抽象出數(shù)據(jù)提供程序。數(shù)據(jù)訪問(wèn)應(yīng)用程序塊利用了這些類,并且提供了加強(qiáng)支持?jǐn)?shù)據(jù)庫(kù)特定特性封裝的模型,例如參數(shù)發(fā)現(xiàn)和類型轉(zhuǎn)換。因此,應(yīng)用程序可以在不修改客戶代碼的情況下從一個(gè)數(shù)據(jù)庫(kù)移植到另一個(gè)數(shù)據(jù)庫(kù)。數(shù)據(jù)訪問(wèn)應(yīng)用程序塊包括一個(gè)抽象基類,它定義了一個(gè)通用的接口,并提供了許多在 ADO.NET 2.0 中可用的數(shù)據(jù)訪問(wèn)方法所需要的實(shí)現(xiàn)。
應(yīng)用程序塊還包含了專用于 Microsfot SQL Server、Microsoft SQL Server CE、和 Oracel 的類。這些類完成對(duì)特定數(shù)據(jù)庫(kù)類型的操作。應(yīng)用程序的代碼只為一種數(shù)據(jù)庫(kù)而編寫,例如 SQL Server,可以看到有許多為另一種數(shù)據(jù)庫(kù)編寫的代碼是一樣的,例如 Oracle 。
數(shù)據(jù)訪問(wèn)應(yīng)用程序塊的另一個(gè)特性是,應(yīng)用程序代碼可以由一個(gè) ADO.NET 連接字符串的名字,如"Customer" 或者 "Inventory" ,而引向一個(gè)特定的數(shù)據(jù)。應(yīng)用程序代碼可以指定一個(gè)數(shù)據(jù)庫(kù)命名實(shí)例,并傳遞此參數(shù)到 DatabaseFactory.CreateDatabase 方法。每個(gè)命名數(shù)據(jù)庫(kù)都有連接字符串保存在配置文件中。通過(guò)修改配置文件中的設(shè)置,開發(fā)人員可以在不同的數(shù)據(jù)庫(kù)配置下使用應(yīng)用程序而不需要重新編譯代碼。
數(shù)據(jù)訪問(wèn)應(yīng)用程序塊提供了下列好處:
- 使用了由 ADO.NET 2.0 提供的功能并與其一起使用,可以同時(shí)使用 ADO.NET 和應(yīng)用程序塊的功能。
- 減少編寫重復(fù)代碼完成標(biāo)準(zhǔn)任務(wù)的需要。
- 有助于維護(hù)一致的數(shù)據(jù)訪問(wèn)實(shí)踐,無(wú)論是在應(yīng)用程序內(nèi)部還是企業(yè)間。
- 減少了變更數(shù)據(jù)庫(kù)類型的困難。
- 將開發(fā)人員從學(xué)習(xí)用于不同數(shù)據(jù)庫(kù)的不同編程模型中解放出來(lái)。
- 減少了在開發(fā)人員移植應(yīng)用程序到另一種數(shù)據(jù)庫(kù)時(shí)不得不編寫的代碼的數(shù)量。
普通場(chǎng)景
開發(fā)人員經(jīng)常編寫使用數(shù)據(jù)庫(kù)的應(yīng)用程序。因?yàn)樗毡榱?#xff0c;開發(fā)人員可能會(huì)發(fā)現(xiàn)他們?yōu)槊總€(gè)應(yīng)用程序在重復(fù)編寫同樣的代碼。另外,這些應(yīng)用程序可能需要與不同的數(shù)據(jù)庫(kù)一起工作。盡管任務(wù)是相同的,代碼也必須適配以適應(yīng)每個(gè)數(shù)據(jù)庫(kù)的編程模型。數(shù)據(jù)訪問(wèn)應(yīng)用程序塊通過(guò)提供完成最常用的數(shù)據(jù)訪問(wèn)任務(wù)的邏輯來(lái)解決這些問(wèn)題。開發(fā)人員僅需要做如下事情:
- 創(chuàng)建一個(gè) database 對(duì)象。
- 提供用于命令的參數(shù),如果需要的話。
- 調(diào)用適當(dāng)?shù)姆椒?#xff0c;這些方法已經(jīng)過(guò)性能優(yōu)化,并且是可移植的。
數(shù)據(jù)訪問(wèn)應(yīng)用程序塊可以透明的與 SQL Server、SQL Server CE、和 Oracle 數(shù)據(jù)庫(kù)一起工作。數(shù)據(jù)訪問(wèn)應(yīng)用程序塊為解決開發(fā)人員在編寫數(shù)據(jù)庫(kù)應(yīng)用程序時(shí)所面對(duì)的絕大多數(shù)普通任務(wù)而設(shè)計(jì)。這些任務(wù)根據(jù)場(chǎng)景進(jìn)行了組織。每個(gè)場(chǎng)景都人出了一個(gè)真實(shí)世界條件下的示例,例如從分類中獲取信息或者未完成銀行事務(wù),描述了條件所要求的數(shù)據(jù)庫(kù)功能,并展示完成任務(wù)的代碼。
根據(jù)場(chǎng)景組織這些任務(wù)的目的是給代碼一些上下文,來(lái)替代展示一組孤立的方法,而沒有它們最好使用在哪兒的意義,場(chǎng)景為代碼提供了一種設(shè)置,將它放置在其應(yīng)用程序必須訪問(wèn)數(shù)據(jù)庫(kù)的許多開發(fā)人員所熟悉的條件中。
場(chǎng)景如下:
- 使用 DataReader 獲取多行數(shù)據(jù)
- 使用 DataSet 獲取多行數(shù)據(jù)
- 運(yùn)行一個(gè)命令并獲取輸出參數(shù)
- 運(yùn)行一個(gè)命令并獲取單值項(xiàng)
- 在一個(gè)事務(wù)中執(zhí)行多個(gè)操作
- 從 SQL Server 中獲取 XML 數(shù)據(jù)
- 使用包含在 DataSet 對(duì)象中的數(shù)據(jù)更新數(shù)據(jù)庫(kù)
示例應(yīng)用程序代碼
下列代碼展示了如何調(diào)用一個(gè)存儲(chǔ)過(guò)程并返回一個(gè) DataSet。
Database db = DatabaseFactory.CreateDatabase();
?
DbCommand dbCommand = db.GetStoredProcCommand("GetProductsByCategory"); ?
// Retrieve products from category 7. db.AddInParameter(dbCommand, "CategoryID", DbType.Int32, 7); ?
DataSet productDataSet = db.ExecuteDataSet(dbCommand);
從3.1版本之后修改的特性
一般情況下,使用數(shù)據(jù)訪問(wèn)應(yīng)用程序塊的早期版本發(fā)布構(gòu)建的應(yīng)用程序不需要修改任何代碼就能使用 May 2008 發(fā)行的功能。可能需要更新引用以指向新的程序集,并更新配置文件以引用正確的應(yīng)用程序版本。然而在version 3.1 (May 2007)所做的一些修改會(huì)影響到你從早期版本遷移到現(xiàn)在的版.下面描述這些改變:
.NET Framework 2.0 TransactionScope 類
已經(jīng)修改某些 Database 類的方法以使用 .NET Framework 2.0 的 TransactionScope 類。這些方法,例如 ExecuteNonQuery ,已通過(guò)用 GetOpenConnection 方法替換掉 GetConnection 方法來(lái)修改為識(shí)別 TransactionScop 實(shí)例的有效時(shí)機(jī)。如果編寫了一個(gè)繼承自 Database 類的類,將需要考慮這些變化來(lái)重寫代碼。如果繼續(xù)使用 GetConnection 方法,將會(huì)收到一個(gè)編譯錯(cuò)誤。
另外,如果應(yīng)用程序使用了 ExecuteXmlReader 方法,可能需要重寫代碼以測(cè)試查看在關(guān)閉連接前 TransactionScope 實(shí)例是否是有效的。
SQL Server Compact Edition
Enterprise Library 3.1 – May 2007 和之后版本支持 SQL Server Compact Edition (CE)。SQL Server CE 提供了精減的關(guān)系數(shù)據(jù)庫(kù)的特性,以用于桌面和移動(dòng)應(yīng)用程序,這些程序需要本地?cái)?shù)據(jù)庫(kù)存儲(chǔ)但又不需要完整的 SQL Server 的功能。
何時(shí)使用數(shù)據(jù)訪問(wèn)應(yīng)用程序塊
?
數(shù)據(jù)訪問(wèn)應(yīng)用程序塊包含少量簡(jiǎn)化絕大多數(shù)訪問(wèn)數(shù)據(jù)庫(kù)的普通方法的方法。每個(gè)方法都封裝了獲取數(shù)據(jù)所需要的邏輯以及管理數(shù)據(jù)庫(kù)連接。如果應(yīng)用程序中使用標(biāo)準(zhǔn)的數(shù)據(jù)訪問(wèn)技術(shù)就可以考慮使用應(yīng)用程序塊。
應(yīng)用程序塊補(bǔ)充了 ADO.NET 2.0 中的代碼,以讓你在不同的數(shù)據(jù)庫(kù)類型中使用同樣的代碼。它包含了用于 SQL Server 和 Oracle 數(shù)據(jù)庫(kù)的類。這些類包含了提供特定數(shù)據(jù)庫(kù)特性如參數(shù)處理和游標(biāo)的實(shí)現(xiàn)的代碼。另外,GenericDatabase 類允許使用應(yīng)用程序塊與任何配置的 ADO.NET 2.0 DbProviderFactory 對(duì)象一起使用。可以通過(guò)添加新的惟數(shù)據(jù)庫(kù)特定特性或者提供已有數(shù)據(jù)庫(kù)自定義實(shí)現(xiàn)的數(shù)據(jù)庫(kù)類型來(lái)擴(kuò)展應(yīng)用程序塊。僅僅需要在在一個(gè)用于目標(biāo)數(shù)據(jù)庫(kù)的 ADO.NET 2.0 DbProviderFactory 類。
何時(shí)直接使用 ADO.NET
數(shù)據(jù)訪問(wèn)應(yīng)用程序塊是 ADO.NET 的一個(gè)補(bǔ)充;而不是替換。應(yīng)用程序塊提供了簡(jiǎn)化和方便,同時(shí)幫助開發(fā)人員以最佳實(shí)踐使用 ADO.NET 。如果應(yīng)用程序需要以特殊的方法獲取數(shù)據(jù),或者代碼需要定制以利用特定于特定數(shù)據(jù)庫(kù)的特性,使用 ADO.NET 可能更適合。
使用數(shù)據(jù)訪問(wèn)應(yīng)用程序塊開發(fā)應(yīng)用程序
首先解釋了如何配置應(yīng)用程序塊并將它添加到應(yīng)用程序中。然后,在關(guān)鍵場(chǎng)景中,解釋了如何在特定場(chǎng)景中使用應(yīng)用程序塊,例如獲取單個(gè)項(xiàng)或者使用 DataSet 對(duì)象獲取多行。最后,在開發(fā)任何細(xì)節(jié)中,給出了關(guān)于如連接管理、參數(shù)處理和處理異常等方面的更多信息。本主題假設(shè)使用的是原始的應(yīng)用程序塊,即沒有擴(kuò)展的。要學(xué)習(xí)如何添加功能,請(qǐng)參見擴(kuò)展和修改數(shù)據(jù)訪問(wèn)應(yīng)用程序塊。
輸入配置信息
下面這些過(guò)程展示了如何配置數(shù)據(jù)訪問(wèn)應(yīng)用程序塊。
此過(guò)程解釋了如何配置數(shù)據(jù)訪問(wèn)應(yīng)用程序塊。與節(jié)點(diǎn)關(guān)聯(lián)的屬性顯示在右邊的面板里。
添加數(shù)據(jù)訪問(wèn)應(yīng)用程序塊
- 打開配置文件。更多信息,請(qǐng)參數(shù)配置應(yīng)用程序塊。
- 右單擊Application Configuration,指向 New ,然后單擊 Data Access Application Block。
下一過(guò)程解釋了如何配置默認(rèn)的數(shù)據(jù)庫(kù)實(shí)例,此實(shí)例在應(yīng)用程序調(diào)用不指定實(shí)例名稱的 DatabaseFactory.CreateDatabase 方法時(shí)使用。
配置默認(rèn)數(shù)據(jù)庫(kù)
- 在右面板中,展開 DefaultDatabase 屬性。
- 為 DefaultDatabase 屬性輸入連接字符串的名稱或者從下拉列表中選擇它。默認(rèn)的連接字符串名稱是 ConnectionString 。
- (可選的)輸入一個(gè)新的名稱來(lái)設(shè)計(jì) Name 屬性,默認(rèn)名稱是 ConnectionString。
- 在 ProviderName 屬性節(jié),如果愿意,可能修改提供程序的名稱。輸入提供程序的名稱或者從下拉列表中選擇它。提供程序的默認(rèn)名稱是 System.Data.SqlClient 。ProviderName 屬性必須是一個(gè)在 DBProviderFactory 類中指定的提供程序的名稱。
下一過(guò)程解釋了如何為命名數(shù)據(jù)庫(kù)實(shí)例創(chuàng)建連接字符串。當(dāng)配置控制臺(tái)保存連接字符串時(shí),它生成了一個(gè)以 name = value 格式保存值對(duì)的以分號(hào)分割的字符串。例如,如果使用配置控制臺(tái)來(lái)用默認(rèn)值生成連接字符串,配置控制臺(tái)臺(tái)將生成下列連接字符串。
Database=Database;Server=(local)\SQLEXPRESS;Integrated Security=SSPI;
配置連接字符串
- 單擊 ConnectionString 節(jié)點(diǎn)。
- (可選的)輸入一個(gè)新的名稱以設(shè)置 Name 屬性,這是 ConnectionString 節(jié)點(diǎn)的名稱。默認(rèn)的名稱是 ConnectionString 。
- (可選的)在 ProviderName 屬性節(jié),修改提供程序的名稱。輸入提供程序的名稱或者從下拉列表中選擇它。默認(rèn)的提供程序的名稱是 System.Data.SqlClient 。ProviderName 屬性必須是一個(gè)指定在 DbProviderFactory 類中的提供程序的名稱。
- 用下列值更新 ConnectionString 屬性。例如:
Database=Database;Server=(local)\SQLEXPRESS;Integrated Security=SSPI
下一過(guò)程展示了如何配置一個(gè) SQL Server CE 數(shù)據(jù)庫(kù)。如果應(yīng)用程序總是使用在配置期間命名的單一文件,這些步驟是合適的。關(guān)于 SQL Server CE 的更多信息,請(qǐng)參見創(chuàng)建數(shù)據(jù)庫(kù)對(duì)象的細(xì)節(jié)。
配置 SQL Server CE
- 右單擊 Custom Provider Mappings,指向 New ,然后單擊 Provider Mapping 。
- 在屬性面板中單擊Nmae,在下拉框中選擇Microsoft.SqlServerCe.Client。
- 在屬性面板中單擊 TypeName 屬性。單擊省略號(hào)(...)按鈕
- 在 Type Selector 中,找到并雙擊 SqlCeDatabase 。
- 在 ConnectionStrings 節(jié)點(diǎn)上右單擊并單擊 New ,然后單擊 Connection String 。
- (可選的)輸入新的名稱以設(shè)置 Name 屬性。這是 ConnectionString 節(jié)點(diǎn)的名稱。默認(rèn)的名稱是 ConnectionString 。
- 在 ProviderName 屬性節(jié),修改提供程序的名稱為 Microsoft.SqlServerCe.Client 。
- 在 ConnectionString 屬性節(jié),輸入理想的 SQL Server CE 連接字符串,例如:
Data Source='C:\MyApp\MyDatabase.sdf'
下一過(guò)程展示了如果添加 Oracle 包。Oracel 包服務(wù)是分組存儲(chǔ)過(guò)程到普通組的一種方式,通常基于它們的功能。當(dāng)應(yīng)用程序調(diào)用在包中的 Oracle 存儲(chǔ)過(guò)程時(shí),代碼必須用包名做為存儲(chǔ)過(guò)程的前綴。例如,要調(diào)用在命名為 Employee_pkg 的包中的名為 GetEmployeeName 的過(guò)程,將調(diào)用 Employee_pkg.GetEmployeeName 。
將這段代碼加入到應(yīng)用程序中將降低可移植性,因?yàn)檎Z(yǔ)法專用于 Oracle 。另一種替換做法是,數(shù)據(jù)訪問(wèn)應(yīng)用程序塊會(huì)用包名做為存儲(chǔ)過(guò)程的前綴。這意味著客戶端代碼在調(diào)用存儲(chǔ)過(guò)程時(shí)不需要指定包名。要做到這一點(diǎn),應(yīng)用程序塊使用在配置文件中的信息。OraclePackage 節(jié)點(diǎn)保存了一個(gè)名稱/前綴對(duì)。名稱是包的名稱,前綴是一個(gè)與包相關(guān)的字符串。所有以指定的前綴開始的存儲(chǔ)過(guò)程都假定在相關(guān)的包內(nèi)。
當(dāng)應(yīng)用程序調(diào)用一個(gè)存儲(chǔ)過(guò)程時(shí),數(shù)據(jù)訪問(wèn)應(yīng)用程序塊檢查看是否以配置文件中的某個(gè)前綴開始。如果是,應(yīng)用程序塊為存儲(chǔ)過(guò)程加上相應(yīng)的包名前綴。(應(yīng)用程序塊將使用找到的第一個(gè)匹配)。如果指定一個(gè)星號(hào)(*)為前綴,關(guān)聯(lián)包將用于所有存儲(chǔ)過(guò)程。
配置 Oracle 包
- 右單擊 ConnectionString ,指向 New ,然后單擊 OraclePackages 。
- 單擊 OraclePackage 。
- 輸入 Oracle 包的名稱以修改 Name 屬性。默認(rèn)為 OraclePackage 。
- 輸入 Prefix 屬性的值。
下一過(guò)程解釋了如何通過(guò)關(guān)聯(lián)提供程序和數(shù)據(jù)庫(kù)全名稱來(lái)添加自定義的提供程序映射。
配置自定義的提供程序
- 右單擊 CustomProviderMappings 節(jié)點(diǎn),指向 New ,然后單擊 ProviderMapping 。
- (可選的)輸入新的名稱以設(shè)置 Name 屬性。輸入提供程序的名稱或從下拉列表中選擇。默認(rèn)的提供程序是 System.Data.SqlClient 。ProviderName 屬性必須是一個(gè)在 DbProviderFactory 類中指定的提供程序名稱。
- 在 TypeName 屬性節(jié)中。單擊省略號(hào)按鈕(...)并使用'Type Selector 選擇 Enterprise Library 數(shù)據(jù)庫(kù)類型的全名稱。
可以手工編輯 XML 數(shù)據(jù),但 Enterprise Library 極大的簡(jiǎn)化了此任務(wù)。如果選擇手工編輯 XML ,則要使用包含在本主題中的模式信息。
配置文件有如下的節(jié)處理程序聲明:
<configSections><section name="dataConfiguration"type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings,Microsoft.Practices.EnterpriseLibrary.Data, Version=4.0.0.0,Culture=neutral, PublicKeyToken=31bf3856ad364e35" /><section name="oracleConnectionSettings" type="Microsoft.Practices.EnterpriseLibrary.Data.Oracle.Configuration.OracleConnectionSettings,Microsoft.Practices.EnterpriseLibrary.Data, Version=4.0.0.0,Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections> 節(jié)處理程序聲明包括配置設(shè)置節(jié)的名稱和處理節(jié)中配置數(shù)據(jù)的節(jié)處理程序的類名。第一個(gè)配置設(shè)計(jì)節(jié)的名稱為 dataConfiguration ,節(jié)處理程序的類名為 DatabaseSettings (在 Microsoft.Practices.EnterpriseLibrary.Data.Configuration 命名空間中)。
第二個(gè)配置設(shè)置節(jié)是 oracleConnectionSettings 。節(jié)處理程序類的名稱為 OracleConnectionSettings (在 Microsoft.Practices.EnterpriseLibrary.Data.Oracle.Configuration 命名空間中 )。
connectionStrings 元素
connectionStrings 元素列出了可被應(yīng)用程序使用的數(shù)據(jù)庫(kù)連接,此元素不是必須的。
屬性和子元素
下面的節(jié)描述了 connectionStrings 元素的屬性和子元素。
add 子元素
add 元素是 connectionStrings 元素的子元素。add 元素添加一個(gè)數(shù)據(jù)庫(kù)連接,此元素不是必須的,可以有多個(gè) add 元素。
providerMappings 子元素
這是一個(gè) dataConfiguration 元素的子元素,只有在通過(guò)派生自 ADO.NET 的 Database 類而不是 GenericDatabase 類的提供程序時(shí)才需要指定提供程序的映射。SQL Server 和 Oracle 數(shù)據(jù)庫(kù)默認(rèn)已配置,所以不需要再在此節(jié)中指定。指定在此節(jié)中的一個(gè)數(shù)據(jù)庫(kù)示例是 SQL Server CE 。
add 子元素
add 是 providerMappings 元素的子元素。add 元素添加一個(gè)數(shù)據(jù)庫(kù)連接。此元素不是必須的,可以有多個(gè) add 元素。
表3 列出了素的屬性
packages 子元素
這是 add 元素的一個(gè)子元素,指定一個(gè) Oracle 的包。此元素是必須的。
add 子元素
這是 packages 元素的一個(gè)子元素。 add 元素添加一個(gè) Oracle 的包。此元素不是必須的。可以有多個(gè) add 元素。
屬性
表 5 列出了 add 子元素的屬性。
添加應(yīng)用程序代碼
數(shù)據(jù)訪問(wèn)應(yīng)用程序塊為支持絕大多數(shù)訪問(wèn)數(shù)據(jù)庫(kù)場(chǎng)景而設(shè)計(jì)。在添加自己的應(yīng)用程序代碼時(shí),請(qǐng)參考在關(guān)鍵場(chǎng)景節(jié)中的場(chǎng)景,然后選擇一種與自己的情況最匹配的方法。使用場(chǎng)景中的代碼,或者如果需要,修改它以適合自己的需要。
首先,必須準(zhǔn)備自己的應(yīng)用程序以使用數(shù)據(jù)訪問(wèn)應(yīng)用程序塊。
準(zhǔn)備應(yīng)用程序
- 添加到數(shù)據(jù)訪問(wèn)應(yīng)用程序塊程序集的引用。在 Visual Studio 中,在解決方案管理器中右單擊項(xiàng)目節(jié)點(diǎn),然后單擊添加引用。單擊瀏覽標(biāo)簽,然后導(dǎo)航到 Microsoft.Practices.EnterpriseLibrary.Data.dll 的位置。選擇程序集,然后單擊確定以添加引用。
- 按同樣的步驟,添加到 Enterprise Library 內(nèi)核程序集 Microsoft.Practices.EnterpriseLibrary.Common.dll 和 Microsoft.Practices.ObjectBuilde2r.dll 的引用。
- (可選的) 要不帶完整的精確的元素引用使用來(lái)自加密應(yīng)用程序塊的元素,可以添加下列的 using 語(yǔ)句(C#)或者 Imports 語(yǔ)句(Visual Basic)到源代碼文件的頂部。
using Microsoft.Practices.EnterpriseLibrary.Data; using System.Data;
創(chuàng)建 Database 對(duì)象
所有數(shù)據(jù)訪問(wèn)方法都相對(duì)于 Database 的對(duì)象。可以使用 DatabaseFactory 來(lái)創(chuàng)建 Database 對(duì)象。由工廠生成的 Database 對(duì)象的特定類型是由應(yīng)用程序的配置信息決定的。
可以使用配置控制臺(tái)指定一個(gè)默認(rèn)的數(shù)據(jù)庫(kù)實(shí)例。在不傳遞數(shù)據(jù)庫(kù)實(shí)例名調(diào)用 CreateDatabase 方法時(shí),DatabaseFactory 創(chuàng)建由默認(rèn)實(shí)例指定的 database 。下列應(yīng)用程序代碼展示了如何創(chuàng)建一個(gè)默認(rèn)實(shí)例的 Database 對(duì)象。
Database db = DatabaseFactory.CreateDatabase();
另一種方法是,應(yīng)用程序代碼可以指定一個(gè)命名的數(shù)據(jù)庫(kù)實(shí)例。例如,如果使用配置控制臺(tái)創(chuàng)建了名為 "Sales" 的實(shí)例,則為特定實(shí)例創(chuàng)建 Database 對(duì)象的代碼可能如下。
Database db = DatabaseFactory.CreateDatabase("Sales"); 如果要?jiǎng)?chuàng)建的數(shù)據(jù)庫(kù)的連接字符串是已知的,也要以放棄應(yīng)用程序的配置信息,而是使用構(gòu)造函數(shù)直接創(chuàng)建 Database 對(duì)象。因?yàn)?Database 類是一個(gè)抽象基類,所以必須構(gòu)建一個(gè)它的派生類型。派生的 Database 類型決定了 ADO.NET 數(shù)據(jù)提供程序。例如,SqlDatabase 類使用 SqlClientFactory 提供程序,SqlCeDatabase 使用 SqlCeProviderFactory 提供程序,以及 OracleDatabase 使用 OracleClientFactory 提供程序。為連接字符串構(gòu)建正確類型的 Database 類是你的責(zé)任。
下列代碼使用提供的連接字符串創(chuàng)建了一個(gè) SqlDatabase 對(duì)象。
// Assume the method GetConnectionString exists in your application and // returns a valid connection string. string myConnectionString = GetConnectionString();SqlDatabase sqlDatabase = new SqlDatabase(myConnectionString);
如果通過(guò)不是 ADO.NET SQL 數(shù)據(jù)提供程序或者 Oracle 數(shù)據(jù)提供程序的數(shù)據(jù)提供程序使用一個(gè)連接字符串,可以創(chuàng)建一個(gè) GenericDatabase 對(duì)象。在創(chuàng)建 GenericDatabase 對(duì)象時(shí),必須支持 DbProviderFactory 對(duì)象。
選擇適當(dāng)?shù)闹剌d方法
每個(gè)數(shù)據(jù)訪問(wèn)方法都有多個(gè)重載。下列描述和指南可以幫助你選擇合適的重載:
- 有可以接受 ADO.NET DbCommand 對(duì)象的重載。這些重載為每個(gè)方法提供了最大的靈活性和控制。
- 有接受存儲(chǔ)過(guò)程名稱和用于存儲(chǔ)過(guò)程參數(shù)值的值集合的重載。這些重載在應(yīng)用程序調(diào)用僅有輸入?yún)?shù)的存儲(chǔ)過(guò)程時(shí)比較方便。
- 有接受 System.Data.CommandType 和表示命令的字符串的重載。這些方便的重載在應(yīng)用程序執(zhí)行不帶參數(shù)的內(nèi)聯(lián) SQL 語(yǔ)句或存儲(chǔ)過(guò)程時(shí)使用。
- 最后,以上每個(gè)重載都包含一個(gè)接受一個(gè)事務(wù)的重載。這允許在一個(gè)已存在的事務(wù)中執(zhí)行方法時(shí)使用需要的重載類型。
每個(gè)關(guān)鍵場(chǎng)景示范了特定方法可用重載之一,許多場(chǎng)景都可以使用其他可用的重載完成。
創(chuàng)建 Database 對(duì)象的細(xì)節(jié)
可以使用工廠創(chuàng)建一個(gè) Database 對(duì)象或者直接構(gòu)建一個(gè)。工廠使用配置信息決定連接字符串、ADO.NET 數(shù)據(jù)提供程序和要構(gòu)建的適當(dāng)?shù)呐缮詳?shù)據(jù)訪問(wèn)應(yīng)用程序塊 Database 的對(duì)象。另一種時(shí),傳遞所有需要的信息給對(duì)象的構(gòu)造函數(shù)直接創(chuàng)建 Database 對(duì)象。
在要使用由 Enterprise Library 支持的保存在某個(gè)位置的配置信息時(shí)或者使用由 ADO.NET 管理的連接字符串時(shí)使用工廠。例如,使用工廠用保存在應(yīng)用程序配置文件中的 <connectionStrings> 節(jié)中的連接字符串信息創(chuàng)建 Database 對(duì)象。也可以使用工廠用保存在另一個(gè)配置源中的連接字符串構(gòu)建一個(gè) Database 對(duì)象。必須使用另一個(gè)默認(rèn)配置源來(lái)配置應(yīng)用程序,以允許工廠用保存在那個(gè)配置源中的連接字符串創(chuàng)建對(duì)象。在從不是默認(rèn)配置源中的某些源中獲取連接字符串時(shí),可以使用構(gòu)建函數(shù)。
CreateDatabase 方法是 DatabaseFactory 類的一個(gè)靜態(tài)方法。工廠基于配置文件中的信息創(chuàng)建一個(gè)正確的 database 類,并返回基類的子類的對(duì)象:Database 到客戶代碼。除非需要特定于特殊數(shù)據(jù)庫(kù)類型的命令,例如 SQL Server ,否則應(yīng)該僅使用 Database 基類的的可用方法以保持應(yīng)用程序所使用的數(shù)據(jù)庫(kù)是不可知的。特定的數(shù)據(jù)庫(kù)派生類型的創(chuàng)建對(duì)應(yīng)用程序代碼而言是透明的,因此,同樣可以不需要考慮所使用的數(shù)據(jù)庫(kù)類型。
可以使用 CreateDatabase 方法來(lái)基于默認(rèn)配置指定創(chuàng)建的數(shù)據(jù)庫(kù)類型。通過(guò)修改默認(rèn)配置,可以使未經(jīng)修改的應(yīng)用程序運(yùn)行于不同的數(shù)據(jù)庫(kù)。
也可以使用命名的數(shù)據(jù)庫(kù)實(shí)例,例如在應(yīng)用程序中的 "Customers" 。工廠使用配置文件中的連接字符串來(lái)查找與特定命名實(shí)例相關(guān)的信息以創(chuàng)建正確的數(shù)據(jù)庫(kù)類型。
如果需要使用某個(gè)或另一個(gè)數(shù)據(jù)庫(kù)特定的命令,就必須通過(guò)向下類型轉(zhuǎn)換(downcasting)指定期望由工廠創(chuàng)建的數(shù)據(jù)庫(kù)類型。
最后,可以忽略應(yīng)用程序的配置信息直接創(chuàng)建一個(gè) DataBase 對(duì)象子類型的 Database 對(duì)象。要做到這一點(diǎn),必須知道要?jiǎng)?chuàng)建的數(shù)據(jù)庫(kù)的類型,以及連接字符串和其他任何子類型需要的信息。
創(chuàng)建默認(rèn)數(shù)據(jù)庫(kù)
不指定參數(shù)的調(diào)用工廠的 CreateDatabase 方法將創(chuàng)建一個(gè)默認(rèn)的 database 。配置文件決定哪個(gè)命名實(shí)例是默認(rèn)實(shí)例。可以使用配置控制臺(tái)修改默認(rèn)實(shí)例。
下列代碼展示了如何創(chuàng)建一個(gè)標(biāo)記為默認(rèn)實(shí)例的 database 對(duì)象。
Database dbSvc = DatabaseFactory.CreateDatabase();
注意
如果配置文件沒有指定默認(rèn)實(shí)例,并且客戶代碼在調(diào)用 CreateDatabase 方法時(shí)也沒有指定參數(shù),應(yīng)用程序塊將拋出異常。
使用實(shí)例
要使用實(shí)例,可以通過(guò)邏輯名稱在應(yīng)用程序代碼中引用 database ,并且修改數(shù)據(jù)庫(kù)配置信息(如位置或連接字符串信息)而不用重新編譯代碼。
下列示例展示了如何使用名稱“Sales”創(chuàng)建 database 。
// Use a named database instance that refers to an arbitrary database type,
// which is determined by configuration information.
Database myDb = DatabaseFactory.CreateDatabase("Sales");
創(chuàng)建特定的 Database 類型
如果必須使用專用于特定數(shù)據(jù)庫(kù)類型的方法,在創(chuàng)建數(shù)據(jù)庫(kù)時(shí)可以指定 database 類型。下列代碼要求工廠創(chuàng)建一個(gè) SqlDatabase 對(duì)象。
// Create a SQL database.
SqlDatabase dbSQL = DatabaseFactory.CreateDatabase("Sales") as SqlDatabase;
同樣,要?jiǎng)?chuàng)建一個(gè) Oracle 數(shù)據(jù)庫(kù),使用 OracleDatabase 。要?jiǎng)?chuàng)建一個(gè) SQL CE 數(shù)據(jù)庫(kù),使用 SqlCeDatabase 類型。
不使用配置創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)
可以通過(guò)提供一個(gè)連接字符串給 database 類構(gòu)造函數(shù)來(lái)不使用配置數(shù)據(jù)的創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)對(duì)象。下列代碼展示了如何創(chuàng)建一個(gè) SqlDatabase 對(duì)象。
// Assume your application contains the routine GetConnectionString.
string myConnectionString = GetConnectionString();
SqlDatabase sqlDatabase = new SqlDatabase(myConnectionString);
下列代碼展示了如何創(chuàng)建一個(gè) GenericDatabase 對(duì)象。必須提供連接字符串和 DbProviderFactory 對(duì)象。在這種情況下,DbProviderFactory 對(duì)象是 OdbcFactory 。
GenericDatabase db = new GenericDatabase(connectionString, OdbcFactory.Instance);
使用 SQL Server CE
SQL Server CE 是一個(gè)小型的、進(jìn)程內(nèi)的數(shù)據(jù)庫(kù),它提供了關(guān)系數(shù)據(jù)庫(kù)的必須功能,目的在于需要本地?cái)?shù)據(jù)存儲(chǔ)但不需要 SQL Server 的完整功能的桌面和移動(dòng)應(yīng)用程序。每個(gè)數(shù)據(jù)庫(kù)都保存在一個(gè)文件中,默認(rèn)情況下,擴(kuò)展名為 .sdf 。使用 CreateFile 方法可以創(chuàng)建一個(gè)新的空數(shù)據(jù)庫(kù),此方法使用來(lái)自連接串的文件名。
對(duì)于 SQL Server CE ,打開一個(gè)連接就是打開數(shù)據(jù)庫(kù)文件。結(jié)果是,為每個(gè)請(qǐng)求創(chuàng)建和釋放連接將非常緩慢。為了避免這些性能問(wèn)題,使用 SQL Server CE 的應(yīng)用程序通常在使用數(shù)據(jù)庫(kù)期間盡可能長(zhǎng)的保存連接打開。
在第一次調(diào)用 Database 類的方法時(shí),提供程序創(chuàng)建一個(gè)附加的 “keep alive”連接,它在內(nèi)存中保持了數(shù)據(jù)庫(kù)引擎。應(yīng)用程序?yàn)槊總€(gè) Database 類方法的調(diào)用打開和關(guān)閉其他的連接,但關(guān)閉這些連接不會(huì)關(guān)閉 “keep alive”連接。
要打開一個(gè)數(shù)據(jù)庫(kù),使用 CreateConnection 方法打開到它的連接。這個(gè)方法創(chuàng)建了 “keep alive”連接。當(dāng)使用完數(shù)據(jù)庫(kù)后,必須使用 CloseSharedConnection 方法關(guān)閉到數(shù)據(jù)庫(kù)的 “keep alive”連接。對(duì)于每個(gè)連接字符串僅有一個(gè) “keep alive”連接,盡管對(duì)于同樣的連接字符串可以有多個(gè)打開的連接。
因?yàn)?SQL Server CE 是一個(gè)進(jìn)程內(nèi)的數(shù)據(jù)庫(kù),對(duì)數(shù)據(jù)庫(kù)的多個(gè)調(diào)用將是快而有效的。SQL Server CE 不支持存儲(chǔ)過(guò)程。如果試圖使用任何 Execute 方法,如 ExecuteScalar 和 ExecuteNonQuery ,以一個(gè)存儲(chǔ)過(guò)程做為參數(shù)的話,應(yīng)用程序塊將拋出異常。不用存儲(chǔ)過(guò)程,可以使用內(nèi)聯(lián)的 SQL 語(yǔ)句來(lái)代替。在此有些 Execute 方法的重載是接受一個(gè) SQL 語(yǔ)句為參數(shù)的。因?yàn)榇鎯?chǔ)過(guò)程不受支持的同樣原因,只能在一個(gè)請(qǐng)求中發(fā)送一條 SQL 語(yǔ)句。
SQL Server CE 有一個(gè)名為 SqlCeResultSet 的特殊結(jié)果集。這是查詢返回的結(jié)果集類型。它支持在數(shù)據(jù)庫(kù)中的查詢、前向和后向移動(dòng)、以及修改數(shù)據(jù)。
關(guān)于 SQL Server CE 的一般信息,請(qǐng)參見 Microsoft Web 站點(diǎn)上的 Microsoft SQL Server: SQL Server 2005 Compact Edition 。相關(guān) API 的信息,請(qǐng)參見 MSDN 上的 System.Data.SqlServerCe 命名空間頁(yè)。
注意 SQL Server CE 僅在完全信任環(huán)境中操作。
通過(guò) TransactionScope 類使用 Oracle
盡管可以通過(guò) Oracle 客戶端來(lái)使用 TransactionScope 類,但事務(wù)總是被處理為分布式事務(wù)而不是輕量級(jí)的事務(wù)。分布式事務(wù)有較高的性能開銷。
.NET Framework 托管的用于 Oracle 的提供程序需要一個(gè)名為 oramts.dll 的文件以使用 TransactionScope 類。更多信息,請(qǐng)參見 Microsoft 幫助和支持 Web 站點(diǎn)。
如果通過(guò) Microsoft 事務(wù)服務(wù)器使用 Oracle,請(qǐng)參見 Oracle Web 站點(diǎn)上的 Oracle Services for MTS以獲得適當(dāng)?shù)南螺d。
使用提示
DatabaseFactory 對(duì)象基于 ADO.NET 的 DbProviderFactory 對(duì)象決定哪種 Database 對(duì)象被創(chuàng)建,DbProviderFactory 與連接字符串相關(guān)聯(lián)。連接字符串保存在配置文件的 <connectionStrings> 節(jié)中。默認(rèn)情況下,應(yīng)用程序塊為 System.Data.SqlClient 類型的數(shù)據(jù)提供程序創(chuàng)建 SqlDatabase 類型的 Database 對(duì)象,為 System.Data.SqlServerCe 類型的數(shù)據(jù)提供程序創(chuàng)建 SqlCeDatabase 類型的對(duì)象,為 System.Data.OracleClient 類型的數(shù)據(jù)提供程序創(chuàng)建 OracleDatabase 類型的對(duì)象,為其他所有數(shù)據(jù)提供程序類型創(chuàng)建 GenericDatabase 類型的對(duì)象。
GenericDatabase 類僅支持由 ADO.NET 提供功能的數(shù)據(jù)庫(kù)提供程序。特別的,支持參數(shù)發(fā)現(xiàn)的數(shù)據(jù)訪問(wèn)重載無(wú)法工作。GenericDatabase 可以由任何 .NET 托管的提供程序使用,包括 .NET Framework 2.0 中的 ODBC 和 OLE-DB 提供程序。可以通過(guò)在配置文件中的配置設(shè)置來(lái)覆蓋數(shù)據(jù)提供程序類型和 Database 對(duì)象類型之間的映射。更多信息,請(qǐng)參見數(shù)據(jù)訪問(wèn)應(yīng)用程序塊的設(shè)計(jì)。
創(chuàng)建 DbCommand 對(duì)象
數(shù)據(jù)訪問(wèn)應(yīng)用程序塊提供了獲取 ADO.NET DbCommand 對(duì)象的的統(tǒng)一方法。應(yīng)用程序塊的數(shù)據(jù)訪問(wèn)方法包含了接受 DbCommand 對(duì)象的重載。如果用 DbCommand 對(duì)象來(lái)使用重載,在調(diào)用存儲(chǔ)過(guò)程時(shí)將可以進(jìn)行更多的控制。例如,如果使用 DbCommand 對(duì)象,就可以使用在輸出參數(shù)中返回多個(gè)結(jié)果的存儲(chǔ)過(guò)程。另外,DbCommand 對(duì)象允許指定存儲(chǔ)過(guò)程的超時(shí)值。
創(chuàng)建 DbCommand 對(duì)象的方法分為二種類型:
- 表示存儲(chǔ)過(guò)程調(diào)用的那些方法(例如,GetCustomers)
- 表示 SQL 文本命令的那些方法(例如,Select CustomerID, Fullname From Customers )
調(diào)用的獲取 DbCommand 對(duì)象的方法由是要執(zhí)行內(nèi)聯(lián)的 SQL 還是調(diào)用存儲(chǔ)過(guò)程來(lái)決定。用于存儲(chǔ)過(guò)程的創(chuàng)建 DbCommand 對(duì)象的方法還提供參數(shù)緩存。關(guān)于參數(shù)緩存的更多信息,請(qǐng)參見處理參數(shù)。
所有 DbCommand 對(duì)象的創(chuàng)建都使用 Database 類的方法,這些方法如下:
- GetStoredProcCommand。此方法用于存儲(chǔ)過(guò)程命令。
- GetSqlStringCommand。此方法用于 SQL 文本命令。
二個(gè)方法都返回一個(gè) DbCommand 對(duì)象。
注意:SQL Server CE 不支持存儲(chǔ)過(guò)程,用內(nèi)聯(lián) SQL 語(yǔ)句來(lái)代替。更多信息,請(qǐng)參見創(chuàng)建 Database 對(duì)象的細(xì)節(jié)。
用于 SQL 語(yǔ)句的 DbCommand對(duì)象
使用 GetSqlStringCommand 方法創(chuàng)建用于內(nèi)聯(lián) SQL 語(yǔ)句的 DbCommand 對(duì)象。特定的 SQL 命令在方法調(diào)用時(shí)做為一個(gè)參數(shù)進(jìn)行傳遞。
下列代碼展示了如何使用 GetSqlStringCommand。
Database db = DatabaseFactory.CreateDatabase();
string sqlCommand = "Select CustomerID, LastName, FirstName From Customers";
DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);
用于存儲(chǔ)過(guò)程的 DbCommand 對(duì)象
要執(zhí)行存儲(chǔ)過(guò)程,必須使用 GetStoredProcCommand 方法來(lái)創(chuàng)建 DbCommand 對(duì)象。要執(zhí)行存儲(chǔ)過(guò)程的名稱在方法調(diào)用時(shí)做為一個(gè)參數(shù)傳遞。
下列代碼展示了如何使用 GetStoredProcCommand。
Database db = DatabaseFactory.CreateDatabase();DbCommand dbCommand = db.GetStoredProcCommand("GetProductsByCategory"); 注意:存儲(chǔ)過(guò)程的參數(shù)受 Database 類的方法的支持。關(guān)于如何使用存儲(chǔ)過(guò)程參數(shù)參數(shù)的更多信息,請(qǐng)參見處理參數(shù)。
?
管理連接
數(shù)據(jù)庫(kù)連接是有限資源,它們的妥善管理對(duì)可擴(kuò)展的應(yīng)用程序來(lái)說(shuō)是必不可少的。僅在需要時(shí)保持連接打開并盡快關(guān)閉是一個(gè)很好的實(shí)踐。根據(jù)設(shè)計(jì),絕大多數(shù)的 Database 類方法在每次調(diào)用時(shí)打開和關(guān)閉到數(shù)據(jù)庫(kù)的連接。因?yàn)?#xff0c;應(yīng)用程序代碼不需要包含用于管理連接的代碼。(默認(rèn)情況下,基于性能的原因,ADO.NET 將連接返回到連接池中,而不是關(guān)閉他們。因此,不需要緩存 Database 對(duì)象。)
例如,ExecuteDataSet 返回包含所有數(shù)據(jù)的 DataSet 對(duì)象。這給了你一個(gè)自己的本地副本。對(duì) ExecuteDataSet 的調(diào)用打開了一個(gè)連接、組裝了一個(gè) DataSet、然后在返回結(jié)果前關(guān)閉連接。
下列代碼示范了 ExecuteDataSet 方法的使用。
Database db = DatabaseFactory.CreateDatabase();
string sqlCommand = "Select ProductID, ProductName From Products";
DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);
// No need to open the connection; just make the call.
DataSet customerDataSet = db.ExecuteDataSet(dbCommand);
然而,在關(guān)閉連接時(shí)有一些未清理的其他情況。一個(gè)例子就是 ExecuteReader 方法。此方法返回實(shí)現(xiàn) IDataReader 接口的對(duì)象。Database 基類有一個(gè)返回 DbDataReader 對(duì)象的默認(rèn)實(shí)現(xiàn)。DbDataReader 對(duì)象被設(shè)計(jì)用來(lái)讀取需要的數(shù)據(jù)的特定部分,它需要一個(gè)打開的連接。換句話說(shuō),它不知道應(yīng)用程序何時(shí)不再需要 DbDataReader 。如果數(shù)據(jù)訪問(wèn)應(yīng)用程序塊在返回 DbDataReader 之前就關(guān)閉了連接,DbDataReader 對(duì)客戶代碼而言是無(wú)用的。因此,DbDataReader 方法指定底層的 ADO.NET 在 DbDataReader 完成后自動(dòng)關(guān)閉連接。在這種情況下,它被認(rèn)為是由應(yīng)用程序確定 DbDataReader 及時(shí)關(guān)閉的最好方法,可以使用 DbDataReader.close 方法顯示的關(guān)閉 reader 或者強(qiáng)制 DbDataReader 的銷毀,這是 Close 方法被調(diào)用的結(jié)果。
下列代碼示范了對(duì) ExecuteReader 方法的調(diào)用。using 語(yǔ)句(在 Visual Basic 中為 Using )確保 DbDataReader 對(duì)象被銷毀,并在銷毀的過(guò)程中關(guān)閉 DbDataReader 對(duì)象。
Database db = DatabaseFactory.CreateDatabase();DbCommand dbCommand = db.GetSqlStringCommand("Select Name, Address From Customers");
using (IDataReader dataReader = db.ExecuteReader(dbCommand))
{
// Process results
} ?
使用 TransactionScope 類
在此對(duì) Database 類的某些方法進(jìn)行了一些修改,以利用 .NET Framework 2.0 的 TransactionScope 類。此類自動(dòng)將數(shù)據(jù)庫(kù)調(diào)用加入到一個(gè)外圍的事務(wù)中。這在將業(yè)務(wù)對(duì)象加入到一個(gè)事務(wù)中而不傳遞事務(wù)到這些業(yè)務(wù)對(duì)象中時(shí)非常有用。以下是 TransactionScope 類的使用的基本模型。
using (TransactionScope scope = new
?????????? TransactionScope(TransactionScopeOption.RequiresNew))
{
??? int rows = db.ExecuteNonQuery(CommandType.Text, insertString);
??? rows = db.ExecuteNonQuery(CommandType.Text, insertString2);
}
二個(gè) ExecuteNonQuery 方法將行插入到了在創(chuàng)建 TransactionScope 實(shí)例時(shí)定義的事務(wù)中。
TransactionScope 類創(chuàng)建了一個(gè)本地的、輕量級(jí)的事務(wù)。它假定為發(fā)生在事務(wù)中的所有的數(shù)據(jù)庫(kù)調(diào)用使用一個(gè)連接。這意味著,做為傳遞 DbTransaction 實(shí)例的另一種方法,簡(jiǎn)單的傳遞連接,然后 .NET Framework 自動(dòng)為執(zhí)行的每個(gè)命令設(shè)置了連接。
Enterprise Library,換句話說(shuō),通常為每個(gè)請(qǐng)求打開并關(guān)閉連接。此方法與 TransactionScope 類工作的方法不兼容。如果有多個(gè)連接,TransactionScope 類將認(rèn)為事務(wù)是分布式事務(wù)。分布式事務(wù)比本地事務(wù)有顯著的性能和資源消耗。
要避免這些,Database 類的方法,如 ExecuteDataSet ,識(shí)別 TransactionScope 實(shí)例活動(dòng)的時(shí)機(jī),并添加 database 調(diào)用到此事務(wù)中。如果事務(wù)的當(dāng)前活動(dòng)是使用 TransactionScope 實(shí)例的結(jié)果,Database 類方法會(huì)使用單一的連接。
特別的,GetOpenConnection 方法替換了 Database 方法中的 OpenConnection 方法,GetOpenConnection 方法返回一個(gè)連接包裝器。如果沒有事務(wù)正在處理,方法將銷毀包裝器。然而,當(dāng)事務(wù)還在處理中時(shí),方法將保持連接打開。
如果使用 ExecuteXmlReader 方法,將測(cè)試看 TransactionScope 實(shí)例是否是活動(dòng)的。此方法將返回保持 reader 使用的連接的 XmlReader 對(duì)象。當(dāng) reader 使用結(jié)束后,最后的方法就是關(guān)閉此連接。然而,如果使用的是 TransactionScope 的實(shí)例,必須不能這么做,因?yàn)殛P(guān)閉此連接并創(chuàng)建一個(gè)新的連接將會(huì)改變輕量級(jí)的事務(wù)為分布式事務(wù)。
注意:多線程中共享在一個(gè) transaction scope 中的同一事務(wù)將導(dǎo)致下列異常:“Transaction context in use by another session.”
創(chuàng)建可移植的數(shù)據(jù)庫(kù)應(yīng)用程序
如果應(yīng)用程序必須工作在多個(gè)數(shù)據(jù)庫(kù)類型下,有些問(wèn)題就必須要考慮。
Oracle
如果使用 LoadDataSet 方法加載數(shù)據(jù),它將不會(huì)轉(zhuǎn)換 Guid 和 Boolean 數(shù)據(jù)類型。這是因?yàn)榧軜?gòu)無(wú)法決定數(shù)據(jù)的值是 Guid 還是簡(jiǎn)單的 bype">">。數(shù)據(jù)將返回為 byte[ 列。
當(dāng)你為返回多個(gè)游標(biāo)的存儲(chǔ)過(guò)程創(chuàng)建 DbCommand 對(duì)象時(shí),必須傳遞一個(gè)對(duì)象數(shù)組到 GetStoredProcCommand 方法。數(shù)組的大小必須與由存儲(chǔ)過(guò)程返回的游標(biāo)數(shù)量相同。例如,下列代碼示范了如何為返回二個(gè)游標(biāo)的存儲(chǔ)過(guò)程傳遞對(duì)象數(shù)組到 GetStoredProcCommand 。
Database db = DatabaseFactory.CreateDatabase();
object results = new object2;
DbCommand dbCommand = db.GetStoredProcCommand("GetCustomersAndSuppliers", results);
如果存儲(chǔ)過(guò)程僅返回一個(gè)游標(biāo),則不必須傳遞對(duì)象數(shù)組。
用于創(chuàng)建可移植數(shù)據(jù)庫(kù)應(yīng)用程序的建議。
在此有一些用于創(chuàng)建可移植數(shù)據(jù)庫(kù)應(yīng)用程序的建議:
- 避免用存儲(chǔ)過(guò)程參數(shù)名使用數(shù)據(jù)庫(kù)專用令牌。用于特定提供程序的 Database 派生類包含了調(diào)整需要的參數(shù)名的代碼。例如,在支持到 SQL Server 數(shù)據(jù)庫(kù)的存儲(chǔ)過(guò)程參數(shù)名中不要包含 "@" 字符。下列代碼展示了如何調(diào)用 AddInParameter 方法通過(guò)名稱 CategoryID 創(chuàng)建參數(shù)。當(dāng)使用 SqlDatabase 對(duì)象執(zhí)行此代碼時(shí),提供程序用 "@" 做為參數(shù)名的開頭。
Database db = DatabaseFactory.CreateDatabase();DbCommand dbCommand = db.GetStoredProcCommand("GetProductsByCategory");db.AddInParameter(dbCommand, "CategoryID", DbType.Int32, 100); - 總是通過(guò) database 對(duì)象獲取參數(shù)值。
- 考慮后端關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)(RDBMS)的大小寫敏感。例如,在 SQL Server 2000 中的字符串比較是大小寫不敏感的,但是在 Oracle 8i 和 DB2 中是大小寫敏感的。要開發(fā)一個(gè)可移植的應(yīng)用程序,就必須編寫自己的比較邏輯為大小寫不敏感的或者強(qiáng)迫應(yīng)用程序僅為在比較操作中使用的列存儲(chǔ)大寫或小寫。
- 避免使用 RDBMS 專用數(shù)據(jù)類型,例如 OracleBlob。
- 在執(zhí)行存儲(chǔ)過(guò)程時(shí)避免使用返回值,而是使用輸出參數(shù)。
- 在添加參數(shù)到參數(shù)集合中時(shí),確認(rèn)在應(yīng)用程序代碼中的順序與數(shù)據(jù)庫(kù)中的順序相匹配。OLE DB 提供程序使用順序來(lái)執(zhí)行存儲(chǔ)過(guò)程而不是名稱,所以以正確的順序添加集合是很重要的。
- 如果在應(yīng)用程序代碼必須使用內(nèi)聯(lián)的 SQL ,確認(rèn) SQL 語(yǔ)法對(duì)于應(yīng)用程序?qū)⑦\(yùn)行的數(shù)據(jù)庫(kù)類型都是可用的。
- 避免傳遞 null 值到值類型的存儲(chǔ)過(guò)程參數(shù)。如果需要通過(guò) SQLJ 存儲(chǔ)過(guò)程使用 DB2 的可移植接口,這些做將可能無(wú)法正常工作。
處理異常
處理異常的策略在任何企業(yè)應(yīng)用程序中都是必不可少的。下列信息將幫助你添加數(shù)據(jù)訪問(wèn)應(yīng)用程序塊到管理異常的方法中去:
- CreateDatabase 方法使用配置信息,其可能的結(jié)果在配置相關(guān)的異常中。
- Database 方法使用 ADO.NET 和底層數(shù)據(jù)庫(kù)提供程序。由 ADO.NET 拋出的異常由數(shù)據(jù)訪問(wèn)應(yīng)用程序塊為度量的目的而捕獲,然后再次拋出。
- 充分處理異常通常要求訪問(wèn)特定的異常類型。可以包
使用 CommandBehavior.CloseConnection 調(diào)用 ExecuteReader。它在 DataReader 關(guān)閉時(shí)關(guān)閉連接。如果在一個(gè) try 塊中使用 ExecuteReader ,可以添加一個(gè) finally 語(yǔ)句并關(guān)閉返回的 DataReader 對(duì)象,就像展示在下列示例中的一樣。
Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand("GetProductsByCategory"); IDataReader dataReader = null; try { //... dataReader = db.ExecuteReader(dbCommand);
}
catch(Exception ex) { // Process exception }
finally { if (dataReader != null)
dataReader.Close();
}
另一種方法是,可以包含 using 語(yǔ)句來(lái)銷毀 DataReader 對(duì)象,這將導(dǎo)致它的關(guān)閉,就像展示在下列示例中一樣。
Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand("GetProductsByCategory"); using (IDataReader dataReader = db.ExecuteReader(dbCommand)) { // Process results }
對(duì)于在 .NET 中的異常管理的設(shè)計(jì)和實(shí)現(xiàn)原則,請(qǐng)參見異常管理架構(gòu)指南。
處理參數(shù)
絕大多數(shù)存儲(chǔ)過(guò)程接受用于輸入存儲(chǔ)過(guò)程或在輸出時(shí)設(shè)置的值的參數(shù)。就像使用 ADO.NET 一樣,數(shù)據(jù)訪問(wèn)應(yīng)用程序塊允許開發(fā)人員指定參數(shù)所有的屬性。這些屬性可以包括方向、數(shù)據(jù)類型和長(zhǎng)度。此方法叫做顯式參數(shù)處理。然而,為了方便,可以僅指定用于輸入?yún)?shù)的值。在這種情況下,應(yīng)用程序塊將查找并提供參數(shù)的屬性。此方法叫參數(shù)發(fā)現(xiàn)。
顯式參數(shù)處理
Database 類包含了不同的用于傳遞參數(shù)到存儲(chǔ)過(guò)程的方法。此類還包含了用于設(shè)置和測(cè)試這些參數(shù)的值的方法。這些方法如下:
- AddParameter。此方法傳遞一個(gè)參數(shù)(輸入或輸出)到存儲(chǔ)過(guò)程。
- AddInParameter。此方法傳遞輸入?yún)?shù)到一個(gè)存儲(chǔ)過(guò)程。
- AddOutParameter。此方法添加了一個(gè)輸出參數(shù)到存儲(chǔ)過(guò)程。
- GetParameterValue。此方法查找指定的參數(shù)的值。
- SetParameterValue。此方法在使用同樣的連接和命令,但有不同的參數(shù)值時(shí)進(jìn)行多個(gè)插入時(shí)設(shè)置指定參數(shù)的值。
下列代碼示范了如何使用 AddInParameter 和 AddOutParameter 指定參數(shù)。
Database db = DatabaseFactory.CreateDatabase(); string sqlCommand = "GetProductDetails"; DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);db.AddInParameter(dbCommand, "ProductID", DbType.Int32, 5); db.AddOutParameter(dbCommand, "ProductName", DbType.String, 50); db.AddOutParameter(dbCommand, "UnitPrice", DbType.Currency, 8);
注意:前面的代碼不包括專用于數(shù)據(jù)庫(kù)類型的參數(shù)名稱令牌。因此,代碼保留了跨多個(gè)不同數(shù)據(jù)庫(kù)提供程序的通用性。當(dāng)此代碼運(yùn)行于 SqlClient 數(shù)據(jù)提供程序時(shí)(并因此使用 SqlDatabase 類),下列代碼將與前面的代碼有著同樣的行為。然而,此代碼不能移植到其他的數(shù)據(jù)類型。
Database db = DatabaseFactory.CreateDatabase(); string sqlCommand = "GetProductDetails"; DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);db.AddInParameter(dbCommand, "@ProductID", DbType.Int32, 5); db.AddOutParameter(dbCommand, "@ProductName", DbType.String, 50); db.AddOutParameter(dbCommand, "@UnitPrice", DbType.Currency, 8);
使用列值做為參數(shù)輸入
UpdateDataSet 方法要求三個(gè)不同的命令:一個(gè)用于插入值,一個(gè)用于修改值,另一個(gè)用于刪除值。通常,這些命令用于存儲(chǔ)過(guò)程而不是 SQL 字符串。它們?cè)谡{(diào)用后保持由存儲(chǔ)過(guò)程使用的參數(shù)。代替指定用于存儲(chǔ)過(guò)程參數(shù)的值,來(lái)自 DataSet 的值被用作輸入。在這種情況下,AddInParameter 的適當(dāng)重載是接受源列做為參數(shù)的方法之一。
下列代碼展示了如何使用列值做為參數(shù)輸入。
Database db = DatabaseFactory.CreateDatabase();DbCommand insertCommand = db.GetStoredProcCommand("AddProduct");
db.AddInParameter(insertCommand, "ProductName", DbType.String, "ProductName", DataRowVersion.Current);
db.AddInParameter(insertCommand, "CategoryID", DbType.Int32, "CategoryID", DataRowVersion.Current);
db.AddInParameter(insertCommand, "UnitPrice", DbType.Currency, "UnitPrice", DataRowVersion.Current); ?
參數(shù)發(fā)現(xiàn)
使用數(shù)據(jù)訪問(wèn)應(yīng)用程序塊,開發(fā)人員可以指定用于參數(shù)的值,而不需要關(guān)于這些參數(shù)的任何其他信息。在使用參數(shù)發(fā)現(xiàn)時(shí),將要指定所有參數(shù),并設(shè)置所有輸出參數(shù)為 NULL 。
下列代碼示范了如何僅通過(guò)指定參數(shù)值而無(wú)其他屬性來(lái)使用 GetStoredProcCommand 。
Database db = DatabaseFactory.CreateDatabase(); string sqlCommand = "UpdateProduct"; DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand, 11, "Queso Cabrales", 4, 25);
關(guān)于每個(gè)參數(shù)的信息(例如,它的數(shù)據(jù)類型)依賴是底層 ADO.NET 方法調(diào)用所需要的。為了提供這些信息,數(shù)據(jù)訪問(wèn)應(yīng)用程序塊使用 ADO.NET 中的 DeriveParameters 方法來(lái)查找參數(shù)信息。
因?yàn)?DeriveParameters 調(diào)用需要到后端數(shù)據(jù)庫(kù)的一次往返,應(yīng)用程序塊還提供了參數(shù)信息緩存。在第一次調(diào)用需要參數(shù)發(fā)現(xiàn)的特定存儲(chǔ)過(guò)程后,關(guān)于每個(gè)參數(shù)的信息都保存到了參數(shù)緩存中。這意味著對(duì)同樣的存儲(chǔ)過(guò)程的后繼調(diào)用將不需要往返。
在使用參數(shù)發(fā)現(xiàn)時(shí),最好的方法是指定所有的輸出參數(shù)為 NULL 。不需要為 Oracle 存儲(chǔ)過(guò)程提供游標(biāo)參數(shù),OracleDatabase 提供了它們。此對(duì)象假設(shè)游標(biāo)參數(shù)是存儲(chǔ)過(guò)程參數(shù)列表中的第一個(gè)參數(shù)。
轉(zhuǎn)載于:https://www.cnblogs.com/sczw-maqing/p/3375806.html
總結(jié)
以上是生活随笔為你收集整理的Enterprise Library 4 数据访问应用程序块的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: “仰谒玉皇帝”下一句是什么
- 下一篇: 编程以外积累: 如何给项目生成类似VS2