下載 PDF
使用 TableAdapter 精靈建立具類型的 DataSet 時,相對應的 DataTable 會包含主資料庫查詢所傳回的資料行。 但有時候,DataTable 需要包含額外的資料行。 在本教學課程中,我們將了解為什麼在需要額外 DataTable 資料行時建議使用預存程序。
簡介
將 TableAdapter 新增至具類型的 DataSet 時,相對應 DataTable 的結構描述是由 TableAdapter 的主查詢所決定。 例如,如果主查詢傳回資料欄位 A、B 和 C,DataTable 就會有三個名為 A、B 和 C 的相對應資料行。除了其主查詢之外,TableAdapter 還可以包含其他查詢,這可根據某些參數傳回資料子集。 例如,除了 ProductsTableAdapter 的主查詢傳回所有產品資訊之外,它還包含 GetProductsByCategoryID(categoryID) 和 GetProductByProductID(productID) 方法,這些方法會根據提供的參數傳回特定產品資訊。
如果所有 TableAdapter 的方法傳回的資料欄位等於或少於主查詢中指定的資料欄位,則 DataTable 結構描述的模型可妥當地反映 TableAdapter 的主查詢。 如果 TableAdapter 方法需要傳回其他資料欄位,則我們應該相應展開 DataTable 的結構描述。 在在使用主記錄符號清單結合詳細資料 DataList 的主要/詳細資料範例教程中,我們新增了一個方法到 CategoriesTableAdapter,其返回了主要查詢中定義的 CategoryID、CategoryName 和 Description 資料欄位,並額外增加了一個報告每個類別所包含產品數量的資料欄位 NumberOfProducts。 我們手動將一個新資料行添加到 CategoriesDataTable,以便從這個新方法中抓取 NumberOfProducts 資料欄位的值。
如 上傳檔案 教學課程中所述,對使用即席 SQL 陳述式的 TableAdapter,以及其方法的資料欄位不完全符合主查詢時,務必小心。 如果重新執行 TableAdapter 組態精靈,它會更新所有 TableAdapter 方法,使其資料欄位清單符合主查詢。 因此,任何具有自訂資料行清單的方法都會回到主查詢的資料行清單,不會傳回預期的資料。 使用預存程序時,不會發生此問題。
在本教學課程中,我們將探討如何擴充 DataTable 結構描述以包含其他資料行。 鑒於使用臨機操作 SQL 陳述式時 TableAdapter 的脆弱性,在本教學課程中,我們將使用預存程序。 如需有關將 TableAdapter 設定為使用預存程序的詳細資訊,請參閱教學課程:為具類型的 DataSet 的 TableAdapter 建立新的預存程序和為具類型的 DataSet 的 TableAdapter 使用現有的預存程序。
步驟 1:將PriceQuartile欄新增至ProductsDataTable
在教學課程《針對具類型 DataSet 的 TableAdapters 建立新的預存程序》中,我們建立了一個命名為NorthwindWithSprocs的具類型 DataSet。 此 DataSet 目前包含兩個 DataTable:ProductsDataTable 和 EmployeesDataTable。
ProductsTableAdapter 具有下列三個方法:
-
GetProducts- 主查詢,這會傳回Products資料表的所有記錄 - 傳回所有具有指定 categoryID 的產品。- `GetProductByProductID(productID) - 傳回具有指定 productID 的特定產品。`
主查詢和兩個額外的方法都會傳回相同的資料欄位,也就是 Products 資料表的所有資料行。 沒有相關的子查詢或 JOIN 從 Categories 或 Suppliers 資料表中提取相關資料。 因此,ProductsDataTable 對於 Products 資料表中每個欄位都有相應的資料行。
對於本教學課程,讓我們將一個名為 GetProductsWithPriceQuartile 的方法新增至 ProductsTableAdapter,該方法會傳回所有產品。 除了標準產品資料欄位之外,GetProductsWithPriceQuartile 也會包含一個 PriceQuartile 資料欄位,指出產品價格屬於哪一個四分位數。 例如,價格在最貴的 25% 的產品,PriceQuartile 值為 1,而價格在最低的 25% 的產品,PriceQuartile 值為 4。 在我們著手建立預存程序以傳回這項資訊之前,我們需要先更新 ProductsDataTable ,以包含一個資料行來存放 GetProductsWithPriceQuartile 方法使用時的 PriceQuartile 結果。
開啟 NorthwindWithSprocs DataSet,並以滑鼠右鍵按一下 ProductsDataTable。 從操作功能表中選擇 [新增],然後挑選 [資料行]。
圖 1: 將新資料行新增至 ProductsDataTable(按一下以檢視完整大小的影像)
這會將新的資料行新增至名為 Column1 且類型為 System.String 的 DataTable。 我們需要將此資料行的名稱更新為 PriceQuartile,並將其類型更新為 System.Int32,因為這將用來保存介於 1 到 4 之間的數字。 在 ProductsDataTable 中選取新增的資料行,然後從 [屬性] 視窗,將 Name 屬性設定為 PriceQuartile,並將 DataType 屬性設定為 System.Int32。
設定新的資料行名稱和資料型別屬性
圖 2:設定新資料行的 Name 和 DataType 屬性 (按一下以檢視完整大小的影像)
如 [圖 2] 所示,可以設定其他屬性,例如資料行中的值是否必須是唯一的,資料行是否為自動遞增,是否允許資料庫 NULL 值等等。 將這些值設定為預設值。
步驟 2:建立 GetProductsWithPriceQuartile 方法
ProductsDataTable 既已更新為包含 PriceQuartile 資料行,我們現在準備好建立 GetProductsWithPriceQuartile 方法。 首先,以滑鼠右鍵按一下 TableAdapter,然後從操作功能表選擇 [新增查詢]。 這會顯示 TableAdapter 查詢組態精靈,它會先提示我們是否要使用臨機操作 SQL 陳述式或新的或現有的預存程序。 由於我們還沒有傳回價格四分位數資料的預存程序,因此讓我們允許 TableAdapter 為我們建立此預存程序。 選取 [建立新預存程序] 選項,然後按 [下一步]。
指示 TableAdapter 精靈建立預存程序給我們
圖 3:指示 TableAdapter 精靈為我們建立預存程序 (按一下以檢視完整大小的影像)
在後續畫面中,如 [圖 4] 所示,精靈會詢問我們要新增的查詢類型。 由於 GetProductsWithPriceQuartile 方法會傳回 Products 資料表中的所有資料行和記錄,請選取會傳回資料列的 SELECT 選項,然後按 [下一步]。
查詢將是返回多行資料的 SELECT 陳述式。
圖 4:我們的查詢將是一個返回多個資料列的 SELECT 陳述式 (按一下以查看完整大小的圖片)
接下來,系統會提示輸入 SELECT 查詢。 在精靈中輸入下列查詢:
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued,
NTILE(4) OVER (ORDER BY UnitPrice DESC) as PriceQuartile
FROM Products
上述查詢使用 SQL Server 2005 的新 NTILE 函式將結果分成四個群組,其中群組是由以遞減順序排序的 UnitPrice 值所決定。
不幸的是,查詢產生器不知道如何剖析 OVER 關鍵字,而且會在剖析上述查詢時顯示錯誤。 因此,在精靈的文字方塊中直接輸入上述查詢,而不要使用查詢產生器。
注意
如需有關 NTILE 和 SQL Server 2005 其他排序函數的詳細資訊,請參閱 ROW_NUMBER (Transact-SQL) 和 SQL Server 2005 線上文件中的排名函數一節。
輸入 SELECT 查詢並按下 下一步 之後,精靈會要求我們為它將建立的預存程序提供名稱。 將新的預存程序命名為 Products_SelectWithPriceQuartile,然後按一下 [下一步]。
為預存程序命名 Products_SelectWithPriceQuartile
圖 5:命名儲存程序 Products_SelectWithPriceQuartile (按一下以檢視完整大小的影像)
最後,系統會提示我們命名 TableAdapter 方法。 將 [填滿 DataTable] 和 [傳回 DataTable] 核取方塊保留為核取狀態,並將方法命名為 FillWithPriceQuartile 和 GetProductsWithPriceQuartile。
為 TableAdapter 的方法命名,然後按一下 [完成]
圖 6:為 TableAdapter 的方法命名 ,然後按一下 [完成] (按一下以檢視完整大小的影像)
指定了 SELECT 查詢並且已為預存程序和 TableAdapter 方法命名之後,按一下 [完成] 以完成精靈。 此時,您可能會從精靈收到一兩個警告,指出 OVER SQL 結構或語句不受支援。 可以忽略這些警告。
完成精靈之後,TableAdapter 應該包含 FillWithPriceQuartile 和 GetProductsWithPriceQuartile 方法,而且資料庫應該包含名為 Products_SelectWithPriceQuartile 的儲存程序。 請花點時間確認 TableAdapter 確實包含這個新方法,而且預存程序已正確新增至資料庫。 檢查資料庫時,如果您沒有看到預存程序,請嘗試以滑鼠右鍵按一下 [預存程序] 資料夾,然後選擇 [重新整理]。
`確認已將新方法新增到 TableAdapter`
圖 7:確認已將新方法新增至 TableAdapter
確定資料庫包含 Products_SelectWithPriceQuartile 預存程序
圖 8:確定資料庫包含該預存程序 (按一下以檢視完整大小的影像)
注意
使用預存程序而非臨機操作 SQL 陳述式的優點之一,就是重新執行 TableAdapter 組態精靈不會修改預存程序資料行清單。 在 TableAdapter 上按一下滑鼠右鍵,從操作選單選擇 [設定] 選項以啟動精靈,然後按下 [完成] 完成精靈以進行確認。 接下來,移至資料庫並檢視 Products_SelectWithPriceQuartile 預存程序。 請注意,其欄位清單尚未修改。 如果我們使用即席 SQL 語句,重新運行 TableAdapter 配置精靈會還原此查詢的欄位清單以符合主查詢的欄位清單,從而從 GetProductsWithPriceQuartile 方法所使用的查詢中移除 NTILE 語句。
當呼叫資料存取層的 GetProductsWithPriceQuartile 方法時,TableAdapter 會執行 Products_SelectWithPriceQuartile 預存程序,並為每個傳回的記錄在 ProductsDataTable 中新增一個資料列。 預存程序傳回的資料欄位會對應到 ProductsDataTable 的欄。 由於預存程序有傳回 PriceQuartile 資料欄位,因此會將其值分配給 ProductsDataTable 的 PriceQuartile 資料行。
對於其查詢未傳回 PriceQuartile 資料欄位的那些 TableAdapter 方法,PriceQuartile 資料行的值是由其 DefaultValue 屬性所指定的值。 如(圖 2)所示,此值會設定為 DBNull,即預設值。 如果您想要不同的預設值,只要據此設定 DefaultValue 屬性即可。 只要確定 DefaultValue 值是在給定的資料行 DataType(亦即 PriceQuartile 資料行中的 System.Int32)是有效的。
此時,我們已執行將其他資料行新增至 DataTable 的必要步驟。 若要確認此額外的資料行是否如預期運作,讓我們建立一個 ASP.NET 頁面,以顯示每個產品的名稱、價格和價位區間。 不過,在我們這麼做之前,必須先更新業務邏輯層,以便納入呼叫 DAL 的 GetProductsWithPriceQuartile 方法的功能。 接下來,我們將在步驟 3 中更新 BLL,然後在步驟 4 中建立 ASP.NET 頁面。
步驟 3:擴增商務邏輯層
在我們從展示層級使用新的 GetProductsWithPriceQuartile 方法之前,應先將相對應的方法新增至 BLL。 開啟 ProductsBLLWithSprocs 類別檔案並加入下列程式碼:
<System.ComponentModel.DataObjectMethodAttribute_
(System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetProductsWithPriceQuartile() As NorthwindWithSprocs.ProductsDataTable
Return Adapter.GetProductsWithPriceQuartile()
End Function
如同 ProductsBLLWithSprocs 中的其他資料擷取方法,GetProductsWithPriceQuartile 方法會直接呼叫 DAL 對應的 GetProductsWithPriceQuartile 方法,並傳回其結果。
步驟 4:在 ASP.NET Web Pages 中顯示價格四分位數資訊
隨著 BLL 新增完成,我們就可以建立 ASP.NET 頁面,以顯示每個產品的價格四分位數。 開啟 AddingColumns.aspx 資料夾中的 AdvancedDAL 頁面,並將 GridView 從 [工具箱] 拖曳至設計工具,將其 ID 屬性設定為 Products。 從 GridView 的 smart tag,將它繫結至名為 ProductsDataSource 的新 ObjectDataSource。 將 ObjectDataSource 設定為使用 ProductsBLLWithSprocs 類別的 GetProductsWithPriceQuartile 方法。 由於這將是唯讀的格線,因此請將 UPDATE、INSERT 和 DELETE 索引標籤中的下拉式清單設定為 [無]。
將 ObjectDataSource 設定為使用 ProductsBLLWithSprocs 類別
ProductsBLLWithSprocs 類別 (
從 GetProductsWithPriceQuartile 方法擷取產品資訊
** 圖 10:從 GetProductsWithPriceQuartile 方法擷取產品資訊 (按此檢視完整影像)
完成 [設定資料來源精靈] 之後,Visual Studio 會自動針對方法傳回的每個資料欄位,新增 BoundField 或 CheckBoxField 到 GridView。 其中一個資料欄位是 PriceQuartile,也就是我們在步驟 1 中新增至 ProductsDataTable 的欄。
編輯 GridView 的欄位,移除除 ProductName、UnitPrice 和 PriceQuartile BoundFields 之外的所有欄位。 設定 UnitPrice BoundField 以將其值格式化為貨幣,並分別將 UnitPrice 和 PriceQuartile BoundFields 靠右對齊和置中對齊。 最後,將其餘 BoundFields HeaderText 屬性分別更新為 Product、Price 和 Price Quartile。 此外,請核取 GridView 智慧標記中的 [啟用排序] 核取方塊。
完成這些修改之後,GridView 和 ObjectDataSource 的宣告式標記看起來應該如下所示:
<asp:GridView ID="Products" runat="server" AllowSorting="True"
AutoGenerateColumns="False" DataKeyNames="ProductID"
DataSourceID="ProductsDataSource">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False"
SortExpression="UnitPrice">
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
<asp:BoundField DataField="PriceQuartile" HeaderText="Price Quartile"
SortExpression="PriceQuartile">
<ItemStyle HorizontalAlign="Center" />
</asp:BoundField>
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProductsWithPriceQuartile"
TypeName="ProductsBLLWithSprocs">
</asp:ObjectDataSource>
[圖 11] 顯示此頁面在透過瀏覽器瀏覽時樣子。 請注意,一開始,產品會依其價格遞減排序,每個產品會指派一個適當的 PriceQuartile 值。 當然,此資料可以依據其他準則來排序,而 [價格四分位數] 資料行值仍舊反映產品相對於價格的排名 (見 [圖 12])。
產品依價格排序
圖 11:產品依價格排序 (按一下以檢視全尺寸影像)
產品依名稱排序
圖 12:產品依名稱排序 (按一下以檢視全尺寸影像)
注意
只要幾行程式碼,我們就可以擴增 GridView,使其根據 PriceQuartile 值自動為產品資料列著色。 我們可以將第一個四分位數中的產品著色為淺綠色、將第二個四分位數著色為淺黃色等。 我鼓勵您花點時間新增這項功能。 如果您需要複習一下如何格式化 GridView,請參閱根據資料自訂格式化教學課程。
替代方法 - 建立另一個 TableAdapter (資料表配接器)
正如我們在本教程中所看到的,當向 TableAdapter 新增一個方法來傳回不同於主查詢資料欄位的其他資料欄位時,我們可以將相應的欄位新增到 DataTable 中。 然而,只有在 TableAdapter 中有少數方法傳回不同資料欄位,以及那些替代資料欄位與主查詢沒有太大差異時,這種方法才有效。
您可以改將另一個 TableAdapter 新增至 DataSet (包含來自第一個 TableAdapter 可傳回不同資料欄位的方法),而不是將資料行新增至 DataTable。 在本教學課程中,與其將 PriceQuartile 資料行新增至 ProductsDataTable(只能由 GetProductsWithPriceQuartile 方法使用),我們不如將額外的 TableAdapter 新增到名為 ProductsWithPriceQuartileTableAdapter 的 DataSet,並使用 Products_SelectWithPriceQuartile 預存程序作為其主要查詢。 需要取得價格四分位數之產品資訊的 ASP.NET 頁面會使用 ProductsWithPriceQuartileTableAdapter,而那些不需要的頁面可以繼續使用 ProductsTableAdapter。
藉由加入新的 TableAdapter,DataTables 不會受影響,且其資料行會準確地鏡像其 TableAdapter 的方法所傳回的資料欄位。 不過,其他 TableAdapter 可能引入重複的工作和功能。 例如,如果那些顯示 PriceQuartile 資料行的 ASP.NET 頁面也需要提供插入、更新和刪除支援,則必須正確設定其 ProductsWithPriceQuartileTableAdapter、InsertCommand、UpdateCommand 和 DeleteCommand 屬性。 雖然這些屬性會鏡像 ProductsTableAdapter,但此組態會產生額外的步驟。 此外,現在有兩種方式可更新、刪除或新增產品至資料庫 - 透過 ProductsTableAdapter 和 ProductsWithPriceQuartileTableAdapter 類別。
本教學課程的下載檔案包含 ProductsWithPriceQuartileTableAdapter 類別在 NorthwindWithSprocs DataSet 中,當中說明了這個替代方法。
摘要
在大部分情況下,TableAdapter 中的所有方法都會傳回同一組資料欄位,但有時候特定的一兩種方法可能需要傳回其他欄位。 例如,在使用主記錄項目列表搭配詳細資料 DataList 的主要/詳細資料顯示教學課程中,我們新增了一個方法到CategoriesTableAdapter,這個方法除了主查詢的資料欄位外,還會傳回NumberOfProducts欄位,顯示與每個類別相關聯的產品數目。 在本教學課程中,我們探討如何在 ProductsTableAdapter 中新增方法,除了主查詢的資料欄位之外,還傳回了 PriceQuartile 欄位。 若要擷取 TableAdapter 方法傳回的其他資料欄位,我們需要將相對應的資料行新增至 DataTable。
如果您打算手動將資料行新增至 DataTable,建議 TableAdapter 使用預存程序。 如果 TableAdapter 使用臨機操作 SQL 陳述式,則每當執行 TableAdapter 組態精靈時,所有方法資料欄位清單都會還原為主查詢所傳回的資料欄位。 此問題不會延伸至預存程序,這正是建議使用預存程序以及在本教學課程中使用它們的原因。
祝您程式設計愉快!
關於作者
斯科特·米切爾,七本 ASP/ASP.NET 書籍和 4GuysFromRolla.com 創始人的作者,自1998年以來一直與Microsoft Web 技術合作。 Scott 擔任獨立顧問、講師和作家。 他的新書是《24小時自學ASP.NET 2.0》。 他可以聯絡到 mitchell@4GuysFromRolla.com。
特別感謝
本教學課程系列已經過許多熱心的檢閱者檢閱。 本教學課程的主要檢閱者是 Randy Schmidt、Jacky Goor、Bernadette Leigh 和 Hilton Giesenow。 有興趣檢閱我即將推出的 MSDN 文章嗎? 如果是,請在 mitchell@4GuysFromRolla.com給我留言。
將新資料行新增至 ProductsDataTable