使用 SqlDataSource 控制項查詢資料 (C#)
在先前的教學課程中,我們已使用 ObjectDataSource 控制項來完全區隔展示層和資料存取層。 從本教學課程開始,我們將著手了解如何將 SqlDataSource 控制項用於無需如此嚴格區隔展示和資料存取的簡單應用程式。
簡介
截至目前為止的所有教學課程,都會使用包含展示層、商業邏輯層和資料存取層在內的多層式架構。 我們在第一個教學課程 (建立資料存取層) 中建立了資料存取層 (DAL),並在第二個教學課程 (建立商業邏輯層) 中建立了商業邏輯層。 從使用 ObjectDataSource 顯示資料教學課程開始,我們已了解如何使用 ASP.NET 2.0 的新款 ObjectDataSource 控制項來透過宣告方式連結來自展示層的架構。
儘管截至目前為止的所有教學課程都使用該架構來運用資料,但您也可以跳過該架構,直接從 ASP.NET 頁面存取、插入、更新和刪除資料庫資料。 此舉會直接將特定的資料庫查詢和商業邏輯置放在網頁中。 對規模極大或極為複雜的應用程式而言,設計、實作和使用多層式架構為成功更新和維護應用程式的重要關鍵。 不過,建立相當簡單且一次性的應用程式時,可能無需開發如此穩固的架構。
ASP.NET 2.0 備有五個內建的資料來源控制項:SqlDataSource、AccessDataSource、ObjectDataSource、XmlDataSource 和 SiteMapDataSource。 SqlDataSource 可用來直接存取和修改來自關聯式資料庫 (包括 Microsoft SQL Server、Microsoft Access、Oracle 和 MySQL 等) 的資料。 在本教學課程和後續的三個教學課程中,我們將著手檢視如何使用 SqlDataSource 控制項、探索如何查詢和篩選資料庫資料,以及了解如何使用 SqlDataSource 來插入、更新和刪除資料。
圖 1:ASP.NET 2.0 包含五個內建的資料來源控制項
比較 ObjectDataSource 和 SqlDataSource
就概念上而言,ObjectDataSource 和 SqlDataSource 控制項皆為資料的 Proxy。 如同使用 ObjectDataSource 顯示資料教學課程所述,ObjectDataSource 中的多個屬性可指出提供資料的物件類型的,當中具備多個方法,只要叫用,就能在基礎物件類型中選取、插入、更新和刪除資料。 設定完 ObjectDataSource 屬性後,就可使用 ObjectDataSource 的 Select()
、Insert()
、Delete()
和 Update()
方法,將 GridView、DetailsView 或 DataList 等資料 Web 控制項繫結至控制項,以便與基礎結構互動。
SqlDataSource 也具備相同的功能,但會針對關聯式資料庫 (而非物件程式庫) 運作。 使用 SqlDataSource 時,我們必須指定要執行的資料庫連接字串和臨機操作 SQL 查詢,或是已儲存的程序,以插入、更新、刪除和擷取資料。 SqlDataSource 的 Select()
、Insert()
、Update()
和 Delete()
方法只要一經叫用,就會連接指定的資料庫,並發出適當的 SQL 查詢。 如同下方圖表所述,這些方法會負責執行連接資料庫、發出查詢和傳回結果等作業。
圖 2:SqlDataSource 會做為資料庫的 Proxy
注意
在本教學課程中,我們將著重探討如何從資料庫擷取資料。 在使用 SqlDataSource 插入、更新和刪除資料教學課程中,我們將著手了解如何設定 SqlDataSource,以支援插入、更新和刪除等作業。
SqlDataSource 和 AccessDataSource 控制項
除了 SqlDataSource 控制項之外,ASP.NET 2.0 也包含 AccessDataSource 控制項。 這兩個不同的控制項,導致許多剛開始使用 ASP.NET 2.0 的開發人員不禁懷疑 AccessDataSource 控制項式專為搭配 Microsoft Access 使用所打造,而 SqlDataSource 控制項則是專為搭配 Microsoft SQL Server 使用所打造。 雖然 AccessDataSource 是專為搭配 Microsoft Access 使用所設計而成,但 SqlDataSource 控制項則能與任何可透過 .NET 存取的關聯式資料庫搭配使用。 這會包括任何符合 OleDb 或 ODBC 規範的資料存放區,例如 Microsoft SQL Server、Microsoft Access、Oracle、Informix、MySQL 和 PostgreSQL 等。
AccessDataSource 和 SqlDataSource 控制項的唯一差異,在於資料庫連結資訊的指定方式。 AccessDataSource 控制項只需使用 Access 資料庫檔案的檔案路徑。 相較之下,SqlDataSource 則需使用完整的連接字串。
步驟 1:建立 SqlDataSource 網頁
在著手探索如何使用 SqlDataSource 控制項來直接使用資料庫資料之前,我們要先花點時間,為本教學課程和後續三個教學課程所使用的網站專案建立 ASP.NET 頁面。 首先要新增名為 SqlDataSource
的新資料夾。 接下來,則要將下列 ASP.NET 頁面新增至該資料夾,請務必讓每個頁面與 Site.master
主版頁面建立關聯:
Default.aspx
Querying.aspx
ParameterizedQueries.aspx
InsertUpdateDelete.aspx
OptimisticConcurrency.aspx
圖 3:為 SqlDataSource 相關教學課程新增 ASP.NET 頁面
如同其他資料夾一樣,SqlDataSource
資料夾中的 Default.aspx
將在所屬小節中列出教學課程。 請記住,SectionLevelTutorialListing.ascx
使用者控制項會提供這項功能。 因此,請將此使用者控制項從 [方案總管] 拖曳至頁面的 [設計] 檢視,以將其新增至 Default.aspx
。
圖 4:將 SectionLevelTutorialListing.ascx
使用者控制項新增至 Default.aspx
(按一下以檢視完整大小的影像)
最後,則要將這四個頁面新增為 Web.sitemap
檔案的項目。 具體來說,請在新增自訂按鈕後,將下列標記新增至 DataList 和重複項 <siteMapNode>
:
<siteMapNode url="~/SqlDataSource/Default.aspx"
title="Using the SqlDataSource Control"
description="Work directly with database data using the SqlDataSource control.">
<siteMapNode url="~/SqlDataSource/Querying.aspx" title="Retrieving Database Data"
description="Examines how to query data from a database that can then be
displayed through a data Web control."/>
<siteMapNode url="~/SqlDataSource/ParameterizedQueries.aspx"
title="Parameterized Queries"
description="Learn how to specify parameterized WHERE clauses in the
SqlDataSource's SELECT statement." />
<siteMapNode url="~/SqlDataSource/InsertUpdateDelete.aspx"
title="Inserting, Updating, and Deleting Database Data"
description="See how to configure the SqlDataSource to include INSERT, UPDATE,
and DELETE statements." />
<siteMapNode url="~/SqlDataSource/OptimisticConcurrency.aspx"
title="Using Optimistic Concurrency"
description="Explore how to augment the SqlDataSource to include support for
optimistic concurrency." />
</siteMapNode>
更新 Web.sitemap
後,請花點時間透過瀏覽器檢視教學課程網站。 現在,左側功能表會包含可編輯、插入和刪除教學課程的項目。
圖 5:網站地圖現在會包含 SqlDataSource 教學課程的項目
步驟 2:新增和設定 SqlDataSource 控制項
首先請開啟 SqlDataSource
資料夾中的 Querying.aspx
頁面,並切換至 [設計] 檢視。 將 SqlDataSource 控制項從 [工具箱] 拖曳至 [設計工具],並將其 ID
設為 ProductsDataSource
。 如同 ObjectDataSource 一樣,SqlDataSource 不會包含任何轉譯輸出,因此會於設計介面上顯示為灰色方塊。 若要設定 SqlDataSource,請按一下 SqlDataSource 智慧標籤的 [設定資料來源] 連結。
圖 6:按一下 SqlDataSource 智慧標籤的 [設定資料來源] 連結
如此就會顯示 SqlDataSource 控制項的 [設定資料來源] 精靈。 雖然精靈的步驟與 ObjectDataSource 控制項的精靈步驟有所差異,兩者的最終目標則完全相同,也就是提供詳細資料,以說明如何透過資料來源擷取、插入、更新和刪除資料。 針對 SqlDataSource,這項作業需要指定要使用的基礎資料庫,並提供臨機操作 SQL 陳述式或預存程序。
第一個精靈步驟會提示我們提供資料庫。 下拉式清單會包含在 Web 應用程式 App_Data
資料夾中找到的資料庫,以及已新增至 [伺服器總管] 中 [資料連線] 節點的資料庫。 由於我們已將 App_Data
資料夾中適用於 NORTHWIND.MDF
資料庫的連接字串新增至專案的 Web.config
檔案中,因此,下拉式清單會包含該連接字串的參考 NORTHWINDConnectionString
。 從下拉式清單選擇這個項目,並按一下 [下一步]。
圖 7:在下拉式清單中選擇 NORTHWINDConnectionString
選擇資料庫後,精靈會要求傳回資料的查詢。 我們可以從資料表或檢視指定資料行,或是輸入自訂 SQL 陳述式或指定預存程序。 您可以透過 [指定自訂 SQL 陳述式或預存程序] 和 [從資料表或檢視指定資料行] 選項按鈕,以切換這個選項。
注意
針對第一個範例,我們要使用 [從資料表或檢視指定資料行] 選項。 我們將在本教學課程中的後續部分回到這個精靈,並探索 [指定自訂 SQL 陳述式或預存程序]。
圖 8 顯示選取 [從資料表或檢視指定資料行] 選項按鈕時的 [設定 Select 陳述式] 畫面。 下拉式清單會包含 Northwind 資料庫中的一組資料表和檢視,而選取的資料表或檢視則會顯示在下方的核取方塊清單中。 在這個範例中,我們要從 Products
資料表傳回 ProductID
、ProductName
和 UnitPrice
資料行。 如同圖 8 所示,選取這些項目後,精靈會顯示所產生的 SQL 陳述式 SELECT [ProductID], [ProductName], [UnitPrice] FROM [Products]
。
圖 8:傳回 Products
資料表的資料
設定好精靈,好讓其傳回 Products
資料表的 ProductID
、ProductName
和 UnitPrice
資料行後,請按一下 [下一步] 按鈕。 您有機會在這個最終畫面中檢查上一個步驟設定的查詢結果。 請按一下 [測試查詢] 按鈕來執行已設定的 SELECT
陳述式,並在方格中顯示結果。
圖 9:按一下 [測試查詢] 按鈕以檢閱您的 SELECT
查詢
若要完成精靈,請按一下 [完成] 。
如同 ObjectDataSource 一樣,SqlDataSource 的精靈只會將值指派給控制項的屬性,也就是 ConnectionString
和 SelectCommand
屬性。 精靈完成後,您的 SqlDataSource 控制項宣告式標記看起來應該會如下方所示:
<asp:SqlDataSource ID="ProductsDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
SelectCommand="SELECT [ProductID], [ProductName], [UnitPrice] FROM [Products]">
</asp:SqlDataSource>
ConnectionString
屬性會提供資訊來說明如何連接資料庫。 這個屬性可指派完整的硬式編碼連接字串值,或指向 Web.config
中的連接字串。 若要參考 Web.config 中的連接字串值,請使用語法 <%$ expressionPrefix:expressionValue %>
。 一般而言,expressionPrefix 為 ConnectionStrings,而 expressionValue 為 Web.config
<connectionStrings>
區段 中的連接字串名稱。 不過,語法可用來參考資源檔案的 <appSettings>
項目或內容。 如需此語法的詳細資訊,請參閱 ASP.NET 運算式概觀。
SelectCommand
屬性會指定要執行以傳回資料的臨機操作 SQL 陳述式或預存程序。
步驟 3:新增資料 Web 控制項並將其繫結至 SqlDataSource
SqlDataSource 設定完成後,即可繫結至資料 Web 控制項,例如 GridView 或 DetailsView。 在本教學課程中,我們將以 GridView 顯示資料。 將 GridView 從 [工具箱] 拖曳至頁面上,並在 GridView 智慧標籤的下拉式清單中選擇資料來源,以將其繫結至 ProductsDataSource
SqlDataSource。
圖 10:新增 GridView 並將其繫結至 SqlDataSource 控制項 (按一下以檢視完整大小的影像)
在 GridView 智慧標籤的下拉式清單中選取 SqlDataSource 控制項後,Visual Studio 會自動針對資料來源控制項傳回的每個資料行,將 BoundField 或 CheckBoxField 新增至 GridView 中。 由於 SqlDataSource 會傳回 ProductID
、ProductName
和 UnitPrice
等三個資料行,GridView 中將有三個欄位。
請花點時間設定 GridView 的三個 BoundFields。 將 ProductName
欄位的 HeaderText
屬性變更為 [產品名稱],並將 UnitPrice
欄位變更為 [價格]。 此外,請將 UnitPrice
欄位的格式設為貨幣。 完成這些修改後,您的 GridView 宣告式標記看起來應該會如下方所示:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsDataSource"
EnableViewState="False">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ProductID"
InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="ProductName" HeaderText="Product Name"
SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="Price"
SortExpression="UnitPrice" DataFormatString="{0:c}"
HtmlEncode="False" />
</Columns>
</asp:GridView>
請透過瀏覽器瀏覽此頁面。 如圖 11 所示,GridView 會列出每個產品的 ProductID
、ProductName
和 UnitPrice
值。
圖 11:GridView 會顯示每個產品的 ProductID
、ProductName
和 UnitPrice
值 (按一下以檢視完整大小的影像)
造訪頁面時,GridView 會叫用其資料來源控制項的 Select()
方法。 使用 ObjectDataSource 控制項時,這會呼叫 ProductsBLL
類別的 GetProducts()
方法。 但使用 SqlDataSource 時,Select()
方法會建立連接指定資料庫的連線,並發出 SelectCommand
(本範例中的 SELECT [ProductID], [ProductName], [UnitPrice] FROM [Products]
)。 SqlDataSource 會傳回其結果,而 GridView 則會隨即列舉該結果,進而在 GridView 中為每個傳回的資料庫記錄建立資料列。
內建的資料 Web 控制項功能和 SqlDataSource 控制項
一般來說,資料 Web 控制項分頁、排序、編輯、刪除和插入等固有功能,都專屬於資料 Web 控制項,且不會與所使用的資料來源控制項相依。 這表示,GridView 可利用內建的分頁、排序、編輯和刪除,無論該功能是否繫結至 ObjectDataSource 或 SqlDataSource。 不過,特定資料 Web 控制項功能則對所使用的資料來源控制項或資料來源控制項的設定相當敏感。
舉例來說,在有效率地分頁大量資料教學課程中,我們曾探討根據預設,資料 Web 控制項的分頁邏輯將如何透過原生方式傳回基礎資料來源的所有記錄,然後依據目前的頁面索引和每頁顯示的記錄數量來顯示適當的記錄子集。 逐頁瀏覽大量的結果集時,這個模型會顯得相當沒有效率。 幸運的是,ObjectDataSource 可設定為支援自訂分頁,如此就能只傳回要顯示的確切記錄子集。 然而,SqlDataSource 控制項則缺少實作自訂分頁的相關屬性。
SqlDataSource 在分頁和排序上還存在另一個微妙的差異。 根據預設,從 SqlDataSource 傳回的資料可透過 GridView 進行分頁或排序。 為了加以示範,請在 Querying.aspx
中核取 GridView 智慧標籤的 [啟用分頁] 和 [啟用排序] 選項,並確認是否如預期般運作。
排序和分頁可正常運作,因為 SqlDataSource 會將資料庫資料擷取至類型鬆散的 DataSet。 您可以從 DataSet 確認實作分頁的重要層面之一,也就是查詢所能傳回的記錄總數。 此外,DataSet 的結果也能透過 DataView 排序。 GridView 要求分頁或排序資料時,SqlDataSource 將自動使用這些功能。
您可以將 SqlDataSource 的 DataSourceMode
屬性 從 DataSet
(預設值) 變更為 DataReader
,藉此將其設定為傳回 DataReader,而非 DataSet。 如果要將 SqlDataSource 的結果傳遞至預期收到 DataReader 的現有程式碼,最好使用 DataReader。 此外,由於 DataReader 是比 DataSet 更加簡單的物件,它們可提供更出色的效能。 然而,如果進行這項變更,資料 Web 控制項將無法進行排序或分頁,原因在於:SqlDataSource 無法確認查詢會傳回多少筆記錄,DataReader 也無法提供任何可排序已傳回資料的技術。
步驟 4:使用自訂的 SQL 陳述式或預存程序
設定 SqlDataSource 控制項時,可在兩個方法之間擇一,將用來傳回資料的查詢指定為自訂 SQL 陳述式或預存程序,或指定為現有資料表或檢視中的資料行。 我們已在步驟 2 中了解如何從 Products
資料表選取資料行。 現在,讓我們看看如何使用自訂 SQL 陳述式。
請將另一個 GridView 控制項新增至 Querying.aspx
頁面,並在智慧標籤的下拉式清單中選擇建立新的資料來源。 接著,請指出資料將從資料庫提取,如此就會建立新的 SqlDataSource 控制項。 請為控制項 ProductsWithCategoryInfoDataSource
命名。
圖 12:建立名為 ProductsWithCategoryInfoDataSource
的新 SqlDataSource 控制項
下一個畫面會要求我們指定資料庫。 請比照圖 7,在下拉式清單中選擇 NORTHWINDConnectionString
,並按一下 [下一步]。 在 [設定 Select 陳述式] 畫面中,選擇 [指定自訂 SQL 陳述式或預存程序] 選項按鈕,並按一下 [下一步]。 這將顯示 [定義自訂陳述式或預存程序] 畫面,當中會提供標示為 SELECT、UPDATE、INSERT 和 DELETE 的索引標籤。 在每個索引標籤中,您可以將自訂 SQL 陳述式輸入至文字方塊內,或從下拉式清單選擇預存程序。 在本教學課程中,我們將探討如何輸入自訂 SQL 陳述式;下一個教學課程則涵蓋使用預存程序的範例。
圖 13:輸入自訂 SQL 陳述式或挑選預存程序
自訂 SQL 陳述式可手動輸入至文字方塊中,或透過按一下 [查詢產生器] 按鈕來透過圖形化方式建構。 在 [查詢產生器] 或文字方塊中,使用下列查詢來傳回 Products
資料表中的 ProductID
和 ProductName
欄位,藉此使用 JOIN
從 Categories
資料表擷取產品的 CategoryName
:
SELECT Products.ProductID, Products.ProductName, Categories.CategoryName
FROM Categories
INNER JOIN Products ON
Categories.CategoryID = Products.CategoryID
圖 14:您可以使用查詢產生器來透過圖形化方式建構查詢
指定查詢後,請按一下 [下一步],以繼續前往 [測試查詢] 畫面。 請按一下 [結束],以完成 SqlDataSource 精靈。
完成精靈後,GridView 將新增三個 BoundField,以顯示從查詢傳回的 ProductID
、ProductName
和 CategoryName
資料行,並產生下列宣告式標記:
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsWithCategoryInfoDataSource"
EnableViewState="False">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ProductID"
InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="ProductName" HeaderText="ProductName"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="CategoryName"
SortExpression="CategoryName" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="ProductsWithCategoryInfoDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
SelectCommand="
SELECT Products.ProductID, Products.ProductName, Categories.CategoryName
FROM Categories
INNER JOIN Products ON Categories.CategoryID = Products.CategoryID">
</asp:SqlDataSource>
圖 15:GridView 會顯示每個產品的 ID、名稱和相關類別名稱 (按一下以檢視完整大小的影像)
摘要
在本教學課程中,我們已了解如何使用 SqlDataSource 控制項來查詢和顯示資料。 如同 ObjectDataSource 一樣,SqlDataSource 也可做為 Proxy,以提供存取資料的宣告式方法。 其屬性會指定要連接的資料庫,以及要執行的 SQL SELECT
查詢;它們可透過 [屬性] 視窗指定,或使用 [設定 DataSource] 精靈指定。
本教學課程中的 SELECT
查詢範例會傳回指定查詢中的所有記錄。 然而,SqlDataSource 控制項則可包括 WHERE
子句,而其參數值能透過程式設計方式指派,或從指定來源自動提取。 在下一個教學課程中,我們將著手了解如何建立和使用參數化查詢!
祝您程式設計愉快!
深入閱讀
如需深入了解本教學課程中探討的多個主題,請參閱下列資源:
關於作者
Scott Mitchell,七本 ASP/ASP.NET 書籍的作者和 4GuysFromRolla.com 創始人,自 1998 年以來便開始使用 Microsoft Web 技術。 Scott 擔任獨立顧問、講師和作家。 他的新書是 Sams Teach Yourself ASP.NET 2.0 in 24 Hours。 您可以透過 mitchell@4GuysFromRolla.com 或他的部落格 (可以在 http://ScottOnWriting.NET 找到) 與他聯繫。
特別感謝
本教學課程系列已經過許多熱心的檢閱者檢閱。 本教學的主要審閱者是 Susan Connery、Bernadette Leigh 和 David Suru。 有興趣檢閱我即將推出的 MSDN 文章嗎? 如果有,請發信到 mitchell@4GuysFromRolla.com 。