設定資料存取層的連線和命令層級設定 (C#)
類別型化資料集中的 TableAdapter 會自動負責連線到資料庫、發出指令以及使用結果填入 DataTable。 然而,有時我們想要自己處理這些細節,在本教學課程中,我們學習如何存取 TableAdapter 中的資料庫連結和命令級設定。
簡介
在整個教學課程系列中,我們使用類別型化資料集來實現分層架構的資料存取層和業務物件。 如第一篇教學中所討論的,Typed DataSet 的 DataTable 充當資料儲存庫,而 TableAdapter 充當包裝器,與資料庫通訊以擷取和修改底層資料。 TableAdapter 封裝了使用資料庫所涉及的複雜性,使我們不必編寫程式碼來連接資料庫、發出命令或將結果填入 DataTable 中。
然而,有時我們需要深入研究 TableAdapter 並編寫直接與 ADO.NET 物件一起工作的程式碼。 例如,在交易內包裝資料庫修改教學中,我們為 TableAdapter 新增了用於開始、提交和回溯 ADO.NET 交易的方法。 這些方法使用指派給 TableAdapter SqlTransaction
物件的內部手動建立的SqlCommand
物件。
在本教學課程中,我們將研究如何存取 TableAdapter 中的資料庫連結和命令級設定。 特別是,我們將添加功能以 ProductsTableAdapter
允許存取底層連接字串和命令逾時設定。
使用 ADO.NET 處理資料
Microsoft .NET Framework 包含大量專為處理資料而設計的類別。 這些位於System.Data
命名空間內的類別稱為 ADO.NET 類別。 ADO.NET 下的一些類別與特定的資料提供者相關聯。 您可以將資料提供者視為允許資訊在 ADO.NET 類別和底層資料儲存之間流動的通訊通道。 有通用的提供程序,例如 OleDb 和 ODBC,也有專門為特定資料庫系統設計的提供程序。 例如,雖然可以使用 OleDb 提供者連接到 Microsoft SQL Server 資料庫,但 SqlClient 提供者的效率要高得多,因為它是專門為 SQL Server 設計和最佳化的。
以程式設計方式存取資料時,通常會使用以下模式:
- 建立與資料庫的連線。
- 發出命令。
- 對於
SELECT
查詢,請使用結果記錄。
有單獨的 ADO.NET 類別用於執行每個步驟。 例如,若要使用 SqlClient 提供者連線到資料庫,請使用該SqlConnection
類別。 若要向資料庫發出 INSERT
、UPDATE
、DELETE
或 SELECT
指令,請使用SqlCommand
類別。
除了在交易中包裝資料庫修改教學之外,我們不必自己編寫任何低階 ADO.NET 程式碼,因為 TableAdapters 自動產生的程式碼包括連接到資料庫、發出命令、擷取資料和執行操作所需的功能。到資料表中。 然而,有時我們可能需要自訂這些低級設定。 在接下來的幾個步驟中,我們將研究如何利用 TableAdapter 內部使用的 ADO.NET 物件。
第 1 步:使用連線屬性進行檢查
每個TableAdapter 類別都有一個指定資料庫連結資訊的Connection
屬性。 此屬性的資料類別型和 ConnectionString
值由 TableAdapter 設定精靈中所做的選擇決定。 回想一下,當我們第一次將 TableAdapter 新增到類別型化資料集中時,精靈會要求我們提供資料庫來源 (請參閱圖 1)。 第一步中的下拉清單包括設定檔中指定的資料庫以及伺服器資源管理器資料連線中的任何其他資料庫。 如果下拉清單中不存在我們要使用的資料庫,可以透過點擊「新連線」按鈕並提供所需的連線資訊來指定新的資料庫連結。
圖 1:TableAdapter 設定精靈的第一步 (點選查看大圖)
讓我們花點時間檢查一下 TableAdapter Connection
屬性的程式碼。 如同在建立資料存取層教學課程所述,我們可以透過前往「類別檢視」窗口,深入對應的類別,然後雙擊成員名稱來查看自動產生的 TableAdapter 程式碼。
透過前往「檢視」功能表並選擇「類別檢視」(或透過輸入 Ctrl+Shift+C) 導覽至「類別檢視」視窗。 從類別檢視視窗的上半部分,深入 NorthwindTableAdapters
命名空間並選擇 ProductsTableAdapter
類別。 這將在類別檢視的下半部顯示 ProductsTableAdapter
成員,如圖 2 所示。 雙擊 Connection
屬性以查看其程式碼。
圖 2:雙擊類別檢視中的 Connection 屬性以查看其自動產生的程式碼
TableAdapter 的 Connection
屬性和其他連線相關的程式碼如下:
private System.Data.SqlClient.SqlConnection _connection;
private void InitConnection() {
this._connection = new System.Data.SqlClient.SqlConnection();
this._connection.ConnectionString =
ConfigurationManager.ConnectionStrings["NORTHWNDConnectionString"].ConnectionString;
}
internal System.Data.SqlClient.SqlConnection Connection {
get {
if ((this._connection == null)) {
this.InitConnection();
}
return this._connection;
}
set {
this._connection = value;
if ((this.Adapter.InsertCommand != null)) {
this.Adapter.InsertCommand.Connection = value;
}
if ((this.Adapter.DeleteCommand != null)) {
this.Adapter.DeleteCommand.Connection = value;
}
if ((this.Adapter.UpdateCommand != null)) {
this.Adapter.UpdateCommand.Connection = value;
}
for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
if ((this.CommandCollection[i] != null)) {
((System.Data.SqlClient.SqlCommand)
(this.CommandCollection[i])).Connection = value;
}
}
}
}
當 TableAdapter 類別被實例化時,成員變數 _connection
等於 null
。 當存取 Connection
屬性時,它首先檢查 _connection
成員變數是否已被實例化。 如果沒有,則呼叫該方法,InitConnection
方法實例化並將 _connection
屬性設定為在 TableAdapter 設定精靈的第一步中指定的連接字串值 ConnectionString
。
Connection
屬性也可以指派給一個 SqlConnection
物件。 這樣做會將新 SqlConnection
物件與每個 TableAdapter SqlCommand
物件相關聯。
第 2 步:公開連接級設定
連線資訊應保持封裝在 TableAdapter 內,且應用程式體系結構中的其他層無法存取。 但是,在某些情況下,TableAdapter 的連線等級資訊需要可存取或可自訂以供查詢、使用者或 ASP.NET 頁面使用。
讓我們擴展 Northwind
DataSetConnectionString
中的 ProductsTableAdapter
,以包含業務邏輯層可以使用的屬性來讀取或更改 TableAdapter 使用的連接字串。
注意
連接字串是指定資料庫連結資訊的字串,例如要使用的提供者、資料庫的位置、驗證憑證和其他與資料庫相關的設定。 有關各種資料儲存和提供者使用的連接字串模式的列表,請參閱 ConnectionStrings.com。
正如建立資料存取層教學課程中所討論的,類別型化資料集的自動生成的類別可以透過使用部分類別來擴展。 首先,在專案中建立一個新的子資料夾,並在該資料夾ConnectionAndCommandSettings
下命名~/App_Code/DAL
。
圖 3:新增名為的子資料夾ConnectionAndCommandSettings
新增一個名為 ProductsTableAdapter.ConnectionAndCommandSettings.cs
的新類別檔案並輸入以下程式碼:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace NorthwindTableAdapters
{
public partial class ProductsTableAdapter
{
public string ConnectionString
{
get
{
return this.Connection.ConnectionString;
}
set
{
this.Connection.ConnectionString = value;
}
}
}
}
此分部類別新增了一個名為 ProductsTableAdapter
類別的 public
屬性,ConnectionString
屬性允許任何層讀取或更新 TableAdapter 底層連接的連接字串。
建立 (並儲存) 此部分類別後,開啟 ProductsBLL
類別。 轉到現有方法之一併輸入內容,然後按句號鍵調出 Adapter
IntelliSense。 您應該會在 IntelliSense 中看到可用的新 ConnectionString
屬性,這表示您可以透過程式設計方式從 BLL 讀取或調整該值。
公開整個連線物件
此分部類別僅公開底層連接物件的一個屬性:ConnectionString
。 如果您想要讓整個連線物件在 TableAdapter 的範圍之外可用,您也可以變更 Connection
屬性的保護等級。 我們在步驟 1 中檢查的自動產生的程式碼顯示 TableAdapter 的 Connection
屬性被標記為 internal
,這表示它只能由同一程式集中的類別存取。 但是,可以透過 TableAdapter 的 ConnectionModifier
屬性來變更此設定。
開啟 Northwind
資料集 ProductsTableAdapter
,按一下設計器中的 ,然後導覽至「屬性」視窗。 在那裡您將看到設定 ConnectionModifier
為其預設值 Assembly
。 若要使 Connection
屬性在類別型化資料集組件外部可用,請將 ConnectionModifier
屬性變更為 Public
。
圖 4:可以透過 Connection
屬性設定屬性的輔助功能等級 ConnectionModifier
(按一下查看大圖)
儲存 DataSet,然後傳回 ProductsBLL
類別。 和以前一樣,轉到 Adapter
現有方法之一併輸入內容,然後按句號鍵調出 IntelliSense。 該清單應包含一個 Connection
屬性,這意味著您現在可以透過程式設計方式從 BLL 讀取或指派任何連線等級設定。
步驟 3:檢查命令相關屬性
TableAdapter 由一個主查詢組成,預設情況下,該查詢具有自動產生的 INSERT
、UPDATE
和 DELETE
陳述式。 此主查詢 INSERT
、UPDATE
和 DELETE
陳述式在 TableAdapter 程式碼中透過 Adapter
屬性作為 ADO.NET 資料適配器物件實作。 與 Connection
屬性一樣,Adapter
屬性的資料類別型由所使用的資料提供者決定。 由於這些教學課程使用 SqlClient 提供程序,因此 Adapter
屬性的類別型為 SqlDataAdapter
。
TableAdapter 的 Adapter
屬性有三個用於發出 SqlCommand
、INSERT
和 UPDATE
陳述式的類別型屬性 DELETE
:
InsertCommand
UpdateCommand
DeleteCommand
SqlCommand
物件負責向資料庫傳送特定查詢,並具有以下屬性:CommandText
,其中包含要執行的即席 SQL 陳述式或預存程序;Parameters
和 SqlParameter
,是物件的集合。 正如我們在建立資料存取層教學課程中看到的,可以透過「屬性」視窗自訂這些命令物件。
除了其主查詢之外,TableAdapter 還可以包含數量可變的方法,這些方法在呼叫時會將指定的命令分派到資料庫。 主查詢的命令物件和所有附加方法的命令物件都儲存在 TableAdapter 的 CommandCollection
屬性中。
讓我們花點時間來看看 Northwind
DataSet 中 ProductsTableAdapter
為這兩個屬性及其支援的成員變數和輔助方法產生的程式碼:
private System.Data.SqlClient.SqlDataAdapter _adapter;
private void InitAdapter() {
this._adapter = new System.Data.SqlClient.SqlDataAdapter();
... Code that creates the InsertCommand, UpdateCommand, ...
... and DeleteCommand instances - omitted for brevity ...
}
private System.Data.SqlClient.SqlDataAdapter Adapter {
get {
if ((this._adapter == null)) {
this.InitAdapter();
}
return this._adapter;
}
}
private System.Data.SqlClient.SqlCommand[] _commandCollection;
private void InitCommandCollection() {
this._commandCollection = new System.Data.SqlClient.SqlCommand[9];
... Code that creates the command objects for the main query and the ...
... ProductsTableAdapter�s other eight methods - omitted for brevity ...
}
protected System.Data.SqlClient.SqlCommand[] CommandCollection {
get {
if ((this._commandCollection == null)) {
this.InitCommandCollection();
}
return this._commandCollection;
}
}
Adapter
和 CommandCollection
屬性的代碼與 Connection
屬性的代碼非常相似。 有一些成員變數保存屬性所使用的物件。 屬性 get
存取器首先檢查對應的成員變數是否為 null
。 如果是這樣,則呼叫初始化方法,該方法會建立成員變數的實例並指派與核心命令相關的屬性。
步驟 4:公開命令級設定
理想情況下,命令級資訊應保持封裝在資料存取層內。 但是,如果體系結構的其他層需要此訊息,則可以透過部分類別公開它,就像連接層級設定一樣。
由於 TableAdapter 只有一個 Connection
屬性,因此公開連線級設定的程式碼相當簡單。 修改指令級設定時,事情會稍微複雜一些,因為 TableAdapter 可以有多個指令物件 - InsertCommand
UpdateCommand
和 DeleteCommand
,以及 CommandCollection
屬性中數量可變的指令物件。 更新命令級設定時,這些設定需要傳播到所有命令物件。
例如,假設 TableAdapter 中有某些查詢需要非常長的時間才能執行。 當使用 TableAdapter 執行這些查詢之一時,我們可能會想要增加命令物件的 CommandTimeout
屬性。 此屬性指定等待指令執行的秒數,預設為 30 秒。
若要允許 BLL 調整CommandTimeout
屬性,請在 ProductsDataTable
使用步驟 2 (ProductsTableAdapter.ConnectionAndCommandSettings.cs
) 中建立的部分類別檔案中新增下列 public
方法:
public void SetCommandTimeout(int timeout)
{
if (this.Adapter.InsertCommand != null)
this.Adapter.InsertCommand.CommandTimeout = timeout;
if (this.Adapter.DeleteCommand != null)
this.Adapter.DeleteCommand.CommandTimeout = timeout;
if (this.Adapter.UpdateCommand != null)
this.Adapter.UpdateCommand.CommandTimeout = timeout;
for (int i = 0; i < this.CommandCollection.Length; i++)
if (this.CommandCollection[i] != null)
this.CommandCollection[i].CommandTimeout = timeout;
}
可以從 BLL 或表示層呼叫此方法,為該 TableAdapter 實例發出的所有命令設定命令逾時。
注意
Adapter
和 CommandCollection
屬性標記為 private
,這表示它們只能從 TableAdapter 內的程式碼存取。 與 Connection
屬性不同,這些存取修飾符是不可設定的。 因此,如果需要向體系結構中的其他層公開命令層級屬性,則必須使用上面討論的分部類別 public
方法來提供讀取或寫入 private
命令物件的方法或屬性。
摘要
類別型化資料集中的 TableAdapter 用於封裝資料存取細節和複雜性。 使用 TableAdapter,我們不必擔心編寫 ADO.NET 程式碼來連接資料庫、發出命令或將結果填入 DataTable 中。 這一切都是自動為我們處理的。
但是,有時我們可能需要自訂低階 ADO.NET 細節,例如更改連接字串或預設連線或命令逾時值。 TableAdapter 具有自動產生的 Connection
、Adapter
和 CommandCollection
屬性,但預設情況下這些屬性是 internal
或 private
。 可以透過使用分部類別擴充 TableAdapter 以包含 public
方法或屬性來公開此內部資訊。 或者,可以透過 TableAdapter 的 Connection
屬性設定 TableAdapter 的 ConnectionModifier
屬性存取修飾符。
快樂程式!
關於作者
Scott Mitchell 是七本 ASP/ASP.NET 書籍的作者和 4GuysFromRolla.com 的創始人,自 1998 年以來一直致力於 Microsoft Web 技術。 史考特是一名獨立顧問、培訓師和作家。 他的最新著作是 Sams Teach Yourself ASP.NET 2.0 in 24 Hours。 您可以撥打 mitchell@4GuysFromRolla.com 聯絡他。或者透過他的部落格, http://ScottOnWriting.NET部落格可以在以下位置找到。
特別感謝
本教學系列得到了許多有用的審閱者的審閱。 本教學課程的主要審閱者是 Burnadette Leigh、S ren Jacob Lauritsen、Teresa Murphy 和 Hilton Geisenow。 有興趣查看我即將發表的 MSDN 文章嗎? 如果是這樣,請留言給我 mitchell@4GuysFromRolla.com。