新增其他 DataTable 資料行 (C#)
使用 TableAdapter 精靈建立具型別數據集時,對應的 DataTable 會包含主資料庫查詢所傳回的數據行。 但在某些情況下,DataTable 需要包含其他數據行。 在本教學課程中,我們將了解當需要其他 DataTable 數據行時,為什麼建議使用預存程式。
簡介
將 TableAdapter 新增至具類型數據集時,對應的 DataTable 架構是由 TableAdapter 的主要查詢所決定。 例如,如果主查詢傳回數據欄位 A、B 和 C,DataTable 就會有三個名為 A、B 和 C 的對應數據行。除了其主要查詢之外,TableAdapter 還可以包含其他查詢,這些查詢可能會根據某些參數傳回數據的子集。 例如,除了傳回所有產品的相關信息的主要查詢之外ProductsTableAdapter
,它也包含和GetProductByProductID(productID)
等GetProductsByCategoryID(categoryID)
方法,其會根據提供的參數傳回特定產品資訊。
讓 DataTable 架構的模型反映 TableAdapter 的主要查詢,如果所有 TableAdapter 方法都傳回的數據欄位與主查詢中指定的數據欄位相同或更少, 如果 TableAdapter 方法需要傳回其他數據欄位,則我們應該據以展開 DataTable 的架構。 在 主要/詳細數據使用主記錄的點符清單與詳細數據清單 教學課程中,我們已將方法新增至 CategoriesTableAdapter
傳回 CategoryID
主要查詢中所定義的 、 CategoryName
和數據 Description
欄位加上 NumberOfProducts
,這是報告與每個類別相關聯產品數目的其他數據欄位。 我們手動將新的數據行新增至 CategoriesDataTable
,以便從這個新方法擷取 NumberOfProducts
數據域值。
如 上傳檔案 教學課程所述,請務必小心使用特定 SQL 語句的 TableAdapters,並具有數據欄位不精確符合主要查詢的方法。 如果重新執行 TableAdapter 組態精靈,它會更新所有 TableAdapter s 方法,使其數據欄位清單符合主要查詢。 因此,具有自定義數據行清單的任何方法都會還原為主要查詢的數據行清單,而不會傳回預期的數據。 使用預存程式時,不會發生此問題。
在本教學課程中,我們將探討如何擴充 DataTable 架構以包含其他數據行。 由於使用臨機操作 SQL 語句時 TableAdapter 的彈性,在本教學課程中,我們將使用預存程式。 如需設定 TableAdapter 以使用預存程式的詳細資訊,請參閱 建立具型別 DataSet s TableAdapters 的新預存程式 教學課程。
步驟 1:將數據行PriceQuartile
新增至ProductsDataTable
在 建立具類型數據集的新預存程式 s TableAdapters 教學課程 中,我們建立了名為 NorthwindWithSprocs
的具型別數據集。 此資料集包含兩個 DataTable: ProductsDataTable
和 EmployeesDataTable
。 ProductsTableAdapter
有下列三種方法:
GetProducts
- 主查詢,它會從Products
數據表傳回所有記錄GetProductsByCategoryID(categoryID)
- 傳回具有指定 categoryID 的所有產品。GetProductByProductID(productID)
- 傳回具有指定 productID 的特定產品。
主要查詢和兩個其他方法都會傳回相同的數據集,也就是數據表中的所有數據 Products
行。 沒有相互關聯的子查詢或JOIN
從 或 Suppliers
數據表提取相關數據Categories
。 因此,具有 ProductsDataTable
數據表中每個欄位的 Products
對應數據行。
在本教學課程中,讓我們將方法新增至 ProductsTableAdapter
傳回所有產品的具名 GetProductsWithPriceQuartile
。 除了標準產品數據欄位之外, GetProductsWithPriceQuartile
也會包含一個 PriceQuartile
數據欄位,指出產品價格落在哪一個四分位數。 例如,價格在最昂貴 25% 的產品會有 PriceQuartile
1 的值,而價格落在底部 25% 的產品則值為 4。 不過,在擔心建立預存程式以傳回這項資訊之前,我們必須先更新 ProductsDataTable
以包含數據行,以在使用 方法時GetProductsWithPriceQuartile
保存PriceQuartile
結果。
NorthwindWithSprocs
開啟 DataSet,然後以滑鼠右鍵按鍵 。 ProductsDataTable
從操作功能表選擇 [新增],然後挑選 [數據行]。
圖 1:將新數據行新增至 ProductsDataTable
(按兩下即可檢視大小完整的影像)
這會將新的數據行新增至類型 System.String
為 Column1 的 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 為我們建立此預存程式。 選取 [建立新的預存程式] 選項,然後按 [下一步]。
圖 3:指示 TableAdapter 精靈建立適用於我們的預存程式, (按兩下即可檢視完整大小的映像)
在後續畫面中,如圖 4 所示,精靈會詢問我們要新增的查詢類型。 GetProductsWithPriceQuartile
由於方法會傳Products
回數據表中的所有數據行和記錄,因此請選取 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 s 的新NTILE
函式,將結果分割成四個群組,其中群組是以遞減順序排序的值所UnitPrice
決定。
不幸的是,查詢產生器不知道如何剖析關鍵詞, OVER
而且會在剖析上述查詢時顯示錯誤。 因此,在精靈的文本框中直接輸入上述查詢,而不使用查詢產生器。
注意
如需 NTILE 和 SQL Server 2005 其他排名函式的詳細資訊,請參閱《在線 SQL Server 叢書》中的 ROW_NUMBER (Transact-SQL) 和排名函式一節。
輸入 SELECT
查詢並按兩下一步之後,精靈會要求我們為其建立的預存程式提供名稱。 將新的預存程式 Products_SelectWithPriceQuartile
命名為 ,然後按 [下一步]。
圖 5:將預存程式 Products_SelectWithPriceQuartile
命名為 (按兩下即可檢視完整大小的映像)
最後,系統會提示您命名 TableAdapter 方法。 讓 [填滿 DataTable] 和 [傳回 DataTable] 複選框保持已核取,並將方法 FillWithPriceQuartile
命名為 和 GetProductsWithPriceQuartile
。
圖 6:將 TableAdapter s 方法命名為 ,然後按兩下 [完成] (按兩下以檢視大小完整的影像)
使用 SELECT
指定的查詢和名為 的預存程式和 TableAdapter 方法,按兩下 [完成] 以完成精靈。 此時,您可能會從精靈收到警告或兩個警告,指出 OVER
不支援 SQL 建構或語句。 您可以忽略這些警告。
完成精靈之後,TableAdapter 應該包含 FillWithPriceQuartile
和 GetProductsWithPriceQuartile
方法,而資料庫應該包含名為的 Products_SelectWithPriceQuartile
預存程式。 請花點時間確認 TableAdapter 確實包含這個新方法,而且預存程式已正確新增至資料庫。 檢查資料庫時,如果您沒有看到預存程式嘗試以滑鼠右鍵按兩下 [預存程式] 資料夾,然後選擇 [重新整理]。
圖 7:確認已將新方法新增至 TableAdapter
圖 8:確定資料庫包含 Products_SelectWithPriceQuartile
預存程式 (按兩下即可檢視大小完整的映像)
注意
使用預存程式而非臨機操作 SQL 語句的優點之一是重新執行 TableAdapter 組態精靈不會修改預存程式數據行清單。 在 TableAdapter 上按下滑鼠右鍵,從操作選單選擇 [設定] 選項以啟動精靈,然後按下 [完成] 以完成此動作來確認。 接下來,移至資料庫並檢視 Products_SelectWithPriceQuartile
預存程式。 請注意,其數據行清單尚未修改。 我們已使用臨機操作 SQL 語句,重新執行 TableAdapter 組態精靈會還原此查詢的數據行清單,以符合主要查詢數據行清單,藉此從方法所使用的 GetProductsWithPriceQuartile
查詢中移除 NTILE 語句。
叫用資料存取層 s GetProductsWithPriceQuartile
方法時,TableAdapter 會 Products_SelectWithPriceQuartile
執行預存程式,並將數據列加入至 ProductsDataTable
每個傳回記錄的 。 預存程式傳回的數據欄位會對應至 ProductsDataTable
s 資料行。 因為有 PriceQuartile
從預存程式傳回的數據欄位,所以其值會指派給 ProductsDataTable
s PriceQuartile
數據行。
對於查詢未傳回 PriceQuartile
數據欄位的 TableAdapter 方法,數據 PriceQuartile
行的值是其 DefaultValue
屬性所指定的值。 如圖 2 所示,此值會設定為 DBNull
,預設值。 如果您想要使用不同的預設值,只要據以設定 DefaultValue
屬性即可。 只要確定值DefaultValue
在數據行 (有效,也就是System.Int32
數據PriceQuartile
行 DataType
) 。
此時,我們已執行將其他數據行新增至 DataTable 的必要步驟。 若要確認此額外數據行如預期般運作,讓我們建立 ASP.NET 頁面,以顯示每個產品名稱、價格和價格四分位數。 不過,在這麼做之前,我們必須先更新商業規則層,以包含呼叫 DAL 方法 GetProductsWithPriceQuartile
的方法。 我們將在步驟 3 中更新 BLL,然後在步驟 4 中建立 ASP.NET 頁面。
步驟 3:增強商業規則層
在使用簡報層的新 GetProductsWithPriceQuartile
方法之前,我們必須先將對應的方法新增至 BLL。 開啟類別 ProductsBLLWithSprocs
檔案,並新增下列程式代碼:
[System.ComponentModel.DataObjectMethodAttribute
(System.ComponentModel.DataObjectMethodType.Select, false)]
public NorthwindWithSprocs.ProductsDataTable GetProductsWithPriceQuartile()
{
return Adapter.GetProductsWithPriceQuartile();
}
就像 中的其他 ProductsBLLWithSprocs
數據擷取方法一樣, GetProductsWithPriceQuartile
方法只會呼叫 DAL 對應的 GetProductsWithPriceQuartile
方法並傳回其結果。
步驟 4:在 ASP.NET 網頁中顯示價格分位數資訊
新增 BLL 之後,我們即可建立 ASP.NET 頁面,以顯示每個產品的價格四分位數。 AddingColumns.aspx
開啟資料夾中的頁面AdvancedDAL
,並將 GridView 從 [工具箱] 拖曳至 Designer,並將其ID
屬性設定為 Products
。 從 GridView 智慧標記,將它系結至名為 ProductsDataSource
的新 ObjectDataSource。 將 ObjectDataSource 設定為使用 ProductsBLLWithSprocs
類別 s GetProductsWithPriceQuartile
方法。 由於這會是唯讀的方格,因此請將 UPDATE、INSERT 和 DELETE 索引標籤標的下拉式清單設定為 [無]) (。
圖 9:將 ObjectDataSource 設定為使用 ProductsBLLWithSprocs
類別 (按鍵即可檢視完整大小的影像)
圖 10:從 GetProductsWithPriceQuartile
方法擷取產品資訊 (按兩下即可檢視完整大小的影像)
完成 [設定數據源精靈] 之後,Visual Studio 會自動將 BoundField 或 CheckBoxField 新增至 GridView,以取得方法所傳回的每個數據欄位。 其中一個數據欄位是 PriceQuartile
,也就是我們在步驟 1 中新增至 ProductsDataTable
的數據行。
編輯 GridView 的字段,移除 、 UnitPrice
和 PriceQuartile
BoundFields 的所有ProductName
欄位。 設定 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
至只有方法) 使用GetProductsWithPriceQuartile
的數據行,而是將額外的 TableAdapter 新增 (至ProductsDataTable
使用預存程式做為其主要查詢的 Products_SelectWithPriceQuartile
DataSetProductsWithPriceQuartileTableAdapter
。 ASP.NET 取得價格分位數產品資訊所需的頁面會使用 ProductsWithPriceQuartileTableAdapter
,而無法繼續使用 的頁面 ProductsTableAdapter
。
藉由新增 TableAdapter,DataTables 會維持不變,而且其數據行會精確地鏡像其 TableAdapter s 方法所傳回的數據欄位。 不過,其他 TableAdapters 可能會引進重複的工作和功能。 例如,如果顯示 PriceQuartile
數據行的那些 ASP.NET 頁面也需要提供插入、更新和刪除支援,則必須 ProductsWithPriceQuartileTableAdapter
正確設定其 InsertCommand
、 UpdateCommand
和 DeleteCommand
屬性。 雖然這些屬性會鏡像 ProductsTableAdapter
,但此設定會引進額外的步驟。 此外,現在有兩種方式可以透過 ProductsTableAdapter
和 ProductsWithPriceQuartileTableAdapter
類別來更新、刪除或新增產品至資料庫。
本教學課程的下載包含 ProductsWithPriceQuartileTableAdapter
DataSet 中的 NorthwindWithSprocs
類別,說明這個替代方法。
摘要
在大部分情況下,TableAdapter 中的所有方法都會傳回相同的一組數據欄位,但有時候特定方法或兩種方法可能需要傳回額外的欄位。 例如,在 [主要/詳細數據使用主記錄的項目符號清單與詳細數據清單] 教學課程中,我們新增了方法 CategoriesTableAdapter
,除了主要查詢的數據字段之外,還傳回一個 NumberOfProducts
字段來報告與每個類別相關聯的產品數目。 在本教學課程中,我們探討如何在 除了主要查詢的數據欄位之外,在中新增傳回PriceQuartile
欄位的方法ProductsTableAdapter
。 若要擷取 TableAdapter 方法所傳回的其他數據欄位,我們需要將對應的數據行新增至 DataTable。
如果您打算手動將數據行新增至 DataTable,建議 TableAdapter 使用預存程式。 如果 TableAdapter 使用臨機操作 SQL 語句,每當執行 TableAdapter 組態精靈時,所有方法數據欄位清單都會還原為主要查詢所傳回的數據欄位。 此問題不會延伸至預存程式,這就是建議使用及在本教學課程中使用的原因。
快樂的程序設計!
關於作者
Scott Mitchell 是 1998 年以來,1998 年與 Microsoft Web 技術合作的 七篇 ASP/ASP.NET 書籍和 4GuysFromRolla.com 作者。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格連到,也可以透過其部落格來存取,網址為 http://ScottOnWriting.NET。
特別感謝
本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Randy Schmidt、Jacky Goor、Bernadette 一和一個 Giesenow。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com。