批次更新 (C#)

作者:Scott Mitchell

下載 PDF

瞭解如何在單一作業中更新多個資料庫記錄。 在 [使用者介面層] 中,我們會建置 GridView,其中每個數據列都可編輯。 在數據存取層中,我們會在交易中包裝多個更新作業,以確保所有更新都成功或所有更新都會回復。

簡介

上述教學課程 中,我們已瞭解如何擴充數據存取層,以新增對資料庫交易的支援。 資料庫交易保證一系列的數據修改語句會被視為一個不可部分完成的作業,以確保所有修改都會失敗或全部都成功。 有了這種低階 DAL 功能,我們就可以開始注意如何建立批次數據修改介面。

在本教學課程中,我們將建置 GridView,其中每個數據列都可編輯 (請參閱圖 1) 。 由於每個數據列都會在其編輯介面中轉譯,因此不需要 [編輯]、[更新] 和 [取消] 按鈕的數據行。 相反地,頁面上有兩個 [更新產品] 按鈕,按兩下時,列舉 GridView 數據列並更新資料庫。

GridView 中的每個數據列都是可編輯的

圖 1:GridView 中的每個資料列都可編輯 (按兩下即可檢視大小完整的影像)

讓我們開始吧!

注意

[執行批次] 匯報 教學課程中,我們使用DataList控件建立批次編輯介面。 本教學課程與先前的教學課程不同,其使用 GridView,而且批次更新是在交易的範圍內執行。 完成本教學課程之後,建議您返回先前的教學課程,並加以更新,以使用上一個教學課程中新增的資料庫交易相關功能。

檢查所有 GridView 資料列可編輯的步驟

插入、更新和刪除數據 的概觀中所述,GridView 提供內建支援,以依數據列編輯其基礎數據。 在內部,GridView 會記下可透過其 EditIndex 屬性編輯哪些數據列。 當 GridView 系結至其數據源時,它會檢查每個數據列,以查看數據列的索引是否等於的值 EditIndex。 如果是,該數據列欄位會使用其編輯介面來轉譯。 針對 BoundFields,編輯介面是 TextBox,其 Text 屬性會指派 BoundField s DataField 屬性所指定的數據欄位值。 針對 TemplateFields,會 EditItemTemplate 用來取代 ItemTemplate

回想一下,當使用者按兩下資料列的 [編輯] 按鈕時,編輯工作流程就會啟動。 這會導致回傳、將 GridView s EditIndex 屬性設定為單擊的數據列索引,並將數據重新系結至方格。 按兩下資料列的 [取消] 按鈕時,在回傳 時, EditIndex 會將 設定為的值 -1 ,再將數據重新系結至方格。 由於 GridView 的數據列會以零開始編製索引,因此設定 EditIndex-1 會以唯讀模式顯示 GridView 的效果。

屬性 EditIndex 適用於個別數據列編輯,但並非設計用於批次編輯。 若要讓整個 GridView 可編輯,我們必須使用其編輯介面來呈現每個數據列。 若要達成此目的,最簡單的方式是建立每個可編輯欄位實作為TemplateField,並在中 ItemTemplate定義其編輯介面。

在接下來的幾個步驟中,我們將建立可完全編輯的 GridView。 在步驟 1 中,我們將從建立 GridView 及其 ObjectDataSource 開始,並將其 BoundFields 和 CheckBoxField 轉換成 TemplateFields。 在步驟 2 和 3 中,我們將編輯介面從 TemplateFields EditItemTemplate 移至其 ItemTemplate

步驟 1:顯示產品資訊

在擔心建立可編輯數據列的 GridView 之前,讓我們先直接顯示產品資訊。 BatchUpdate.aspx開啟資料夾中的頁面BatchData,然後將 GridView 從 [工具箱] 拖曳至 Designer。 將 GridView 設為 IDProductsGrid ,並從其智慧標記中選擇將其系結至名為 ProductsDataSource的新 ObjectDataSource。 設定 ObjectDataSource,以從 ProductsBLL 類別 s GetProducts 方法擷取其數據。

將 ObjectDataSource 設定為使用 ProductsBLL 類別

圖 2:將 ObjectDataSource 設定為使用 ProductsBLL 類別 (按兩下即可檢視大小完整的映射)

使用 GetProducts 方法擷取產品數據

圖 3:使用 GetProducts 方法擷取產品數據 (按兩下即可檢視大小完整的影像)

就像 GridView 一樣,ObjectDataSource 的修改功能是設計成以每個數據列為基礎運作。 為了更新一組記錄,我們必須在 ASP.NET 頁的程式代碼後置類別中撰寫一些程式代碼,以批處理數據並將其傳遞至 BLL。 因此,將 ObjectDataSource s UPDATE、INSERT 和 DELETE 索引標籤標的下拉式清單設定為 [無]) (。 按一下 [完成] 以完成精靈。

將 UPDATE、INSERT 和 DELETE 索引標籤中的 Drop-Down 清單 設定為 [無] ()

圖 4:將 UPDATE、INSERT 和 DELETE 索引標籤中的 Drop-Down 清單 設定為 ([無]) (按兩下即可檢視大小完整的映像)

完成 [設定數據源精靈] 之後,ObjectDataSource 的宣告式標記看起來應該如下所示:

<asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>

完成 [設定數據源精靈] 也會讓 Visual Studio 為 GridView 中的產品數據字段建立 BoundFields 和 CheckBoxField。 在本教學課程中,我們只允許用戶檢視和編輯產品名稱、類別、價格和已停止的狀態。 移除 、、 和 欄位,ProductName並將前三個字段的屬性分別重新命名HeaderText為 Product、Category 和 Price。DiscontinuedUnitPriceCategoryName 最後,核取 GridView 智慧標記中的 [啟用分頁] 和 [啟用排序] 複選框。

此時 GridView 有三個 BoundFields (ProductNameCategoryNameUnitPrice) 和 CheckBoxField (Discontinued) 。 我們需要將這些四個字段轉換成 TemplateFields,然後將編輯介面從 TemplateField s EditItemTemplate 移至其 ItemTemplate

注意

我們在 自定義數據修改介面 教學課程中探索了建立和自定義TemplateFields。 我們將逐步解說將 BoundFields 和 CheckBoxField 轉換成 TemplateFields,並在其 ItemTemplate 中定義其編輯介面的步驟,但如果您遇到停滯或需要重新整理,請不要想要回頭參閱本先前的教學課程。

從 GridView 的智慧標記中,按兩下 [編輯資料行] 連結以開啟 [欄位] 對話方塊。 接下來,選取每個欄位,然後按兩下 [將此字位轉換成TemplateField] 連結。

將現有的 BoundFields 和 CheckBoxField 轉換成 TemplateField

圖 5:將現有的 BoundFields 和 CheckBoxField 轉換成 TemplateField

現在,每個欄位都是 TemplateField,我們已準備好將編輯介面從 EditItemTemplate s ItemTemplate 移至 s。

步驟 2:建立ProductNameUnitPrice編輯Discontinued介面

ProductName建立、 UnitPriceDiscontinued 編輯介面是此步驟的主題,而且相當簡單,因為範本欄位 s EditItemTemplate中已經定義每個介面。 CategoryName建立編輯介面較為相關,因為我們需要建立適用類別的DropDownList。 此 CategoryName 編輯介面會在步驟 3 中處理。

讓我們從 ProductName TemplateField 開始。 按下 GridView 智慧標記中的 [編輯範本] 連結,然後向下切入至 ProductName TemplateField s EditItemTemplate。 選取 TextBox,將它複製到剪貼簿,然後將它貼到 ProductName TemplateField s ItemTemplate。 將 TextBox 的 ID 屬性變更為 ProductName

接下來,將 RequiredFieldValidator 新增至 ItemTemplate ,以確保使用者為每個產品名稱提供值。 將 ControlToValidate 屬性設定為 ProductName,屬性 ErrorMessage 必須提供產品名稱。 Text和屬性為 *。 將這些新增專案新增至 ItemTemplate之後,您的畫面看起來應該類似圖 6。

ProductName TemplateField 現在包含 TextBox 和 RequiredFieldValidator

圖 6ProductName TemplateField 現在包含 TextBox 和 RequiredFieldValidator (按兩下即可檢視大小完整的影像)

UnitPrice針對編輯介面,請先從 將 TextBox 從 EditItemTemplateItemTemplate複製到 。 接下來,將 $ 放在 TextBox 前面,並將其 ID 屬性設定為 UnitPrice,並將其 Columns 屬性設定為 8 。

同時將 CompareValidator 新增至 UnitPrice s ItemTemplate ,以確保使用者輸入的值是大於或等於 $0.00 的有效貨幣值。 將驗證程式的 ControlToValidate 屬性設定為 UnitPrice,其 ErrorMessage 屬性必須輸入有效的貨幣值。 請省略任何貨幣符號。,其 Text 屬性為 *,其 Type 屬性Currency為 ,其 屬性為 GreaterThanEqual,並將其 OperatorValueToCompare 屬性設為 0 。

新增 CompareValidator 以確保輸入的價格是非負值貨幣值

圖 7:新增 CompareValidator 以確保輸入的價格是非負值, (按兩下即可檢視大小完整的影像)

針對 TemplateField, Discontinued 您可以使用 中 ItemTemplate已定義的 CheckBox。 只要將其 ID 設定為 [已停止],並將其 Enabled 屬性設定為 true

步驟 3:建立CategoryName編輯介面

TemplateField s EditItemTemplate 中的CategoryName編輯介面包含顯示數據欄位值的 CategoryName TextBox。 我們需要將此取代為列出可能類別的DropDownList。

注意

自定義數據修改介面教學課程包含更完整且更完整的討論,說明如何自定義範本以包含DropDownList,而不是TextBox。 雖然這裡的步驟已完成,但會以非常的方式呈現。 如需建立和設定類別DropDownList的更深入探討,請參閱 自定義數據修改介面 教學課程。

將 DropDownList 從 [工具箱] 拖曳至 CategoryName TemplateField s ItemTemplate,將其 ID 設定為 Categories。 此時,我們通常會透過其智慧標記定義DropDownLists資料源,以建立新的 ObjectDataSource。 不過,這會在 中 ItemTemplate新增 ObjectDataSource,這會導致針對每個 GridView 數據列建立 ObjectDataSource 實例。 相反地,讓我們在 GridView s TemplateFields 之外建立 ObjectDataSource。 結束範本編輯,並將 ObjectDataSource 從 [工具箱] 拖曳至 ObjectDataSource 下方ProductsDataSource的 Designer。 將新的 ObjectDataSource CategoriesDataSource 命名為 ,並將其設定為使用 CategoriesBLL 類別 s GetCategories 方法。

將 ObjectDataSource 設定為使用 CategoriesBLL 類別

圖 8:將 ObjectDataSource 設定為使用 CategoriesBLL 類別 (按兩下即可檢視大小完整的映射)

使用 GetCategories 方法擷取類別數據

圖 9:使用 GetCategories 方法擷取類別數據 (按兩下以檢視大小完整的影像)

由於此 ObjectDataSource 只是用來擷取數據,因此請將 UPDATE 和 DELETE 索引卷標的下拉式清單設定為 ([無]) 。 按一下 [完成] 以完成精靈。

將 UPDATE 和 DELETE 索引標籤中的 Drop-Down 清單 設定為 [無] ()

圖 10:將 [更新] 和 [刪除] 索引標籤中的 Drop-Down 清單 設定為 ([無]) (按鍵即可檢視完整大小的映像)

完成精靈之後, CategoriesDataSource 宣告式標記看起來應該如下所示:

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

建立並設定后 CategoriesDataSource ,返回 CategoryName TemplateField s ItemTemplate ,然後從 DropDownList 的智慧標記單擊 [選擇數據源] 連結。 在 [數據源組態精靈] 中,從第一個下拉式清單中選取 CategoriesDataSource 選項,並選擇 CategoryName 用於顯示和 CategoryID 作為值。

將 DropDownList 系結至 CategoriesDataSource

圖 11:將DropDownList系結至 CategoriesDataSource (按一下以檢視大小完整的映像)

此時, Categories DropDownList 會列出所有類別,但尚未自動為系結至 GridView 資料列的產品選取適當的類別。 若要達成此目的,我們需要將 Categories DropDownList s SelectedValue 設定為產品 CategoryID 的值。 按兩下DropDownList智慧標記中的 [編輯 DataBindings] 連結,並將屬性與CategoryID數據欄位產生關聯SelectedValue,如圖 12 所示。

將 Product s CategoryID 值系結至 DropDownList s SelectedValue 屬性

圖 12:將 Product s CategoryID 值系結至 DropDownList s SelectedValue 屬性

最後一個問題 CategoryID 是:如果產品沒有指定值,則 上的數據系結語句 SelectedValue 將會導致例外狀況。 這是因為DropDownList只包含類別的專案,而且不會為具有 NULL 資料庫值的 CategoryID這些產品提供選項。 若要解決此問題,請將DropDownList的 AppendDataBoundItems 屬性設定為 true ,並將新專案新增至DropDownList,省略 Value 宣告式語法中的屬性。 也就是說,請確定 Categories DropDownList的宣告式語法如下所示:

<asp:DropDownList ID="Categories" runat="server" AppendDataBoundItems="True" 
    DataSourceID="CategoriesDataSource" DataTextField="CategoryName" 
    DataValueField="CategoryID" SelectedValue='<%# Bind("CategoryID") %>'>
    <asp:ListItem Value=">-- Select One --</asp:ListItem>
</asp:DropDownList>

<asp:ListItem Value=""> 請注意 -- 選取一個 -- 屬性Value如何明確地設定為空字串。 請參閱 自定義數據修改介面 教學課程,以取得處理案例所需的額外DropDownList專案 NULL 原因,以及為何將屬性指派 Value 給空字串是必要的。

注意

這裡有值得注意的潛在效能和延展性問題。 由於每個數據列都有一個DropDownList,使用 CategoriesDataSource 做為其數據源,因此 CategoriesBLL 每個頁面流覽都會呼叫類別 s GetCategories 方法 n 次,其中 n 是 GridView 中的數據列數目。 這些 n 呼叫會產生 GetCategories 對資料庫的 n 個查詢。 藉由快取每個要求快取中的傳回類別,或使用 SQL 快取相依性或非常短的時間型到期,快取傳回的類別,可能會降低對資料庫的影響。

步驟 4:完成編輯介面

我們已對 GridView 範本進行一些變更,而不需要暫停即可檢視進度。 請花一點時間檢視瀏覽器的進度。 如圖 13 所示,每個數據列都會使用其 ItemTemplate轉譯,其中包含儲存格的編輯介面。

每個 GridView 數據列都是可編輯的

圖 13:每個 GridView 數據列都是可編輯的, (按兩下即可檢視完整大小的影像)

此時,我們應該處理一些次要格式問題。 首先,請注意此值 UnitPrice 包含四個小數點。 若要修正此問題,請返回 UnitPrice TemplateField s ItemTemplate ,然後從 TextBox 智慧標記按兩下 [編輯 DataBindings] 連結。 接下來,指定 Text 屬性應該格式化為數位。

將 Text 屬性格式化為數位

圖 14:將屬性格式化 Text 為數位

其次,讓我們將數據行中的複選框置中 Discontinued (,而不是讓它靠左對齊) 。 按兩下 GridView 智慧標記中的 [編輯資料行],然後從左下角的欄位清單中選取 Discontinued TemplateField。 向下切入 ItemStyle 並將 HorizontalAlign 屬性設定為 Center,如圖 15 所示。

置中已停止的 CheckBox

圖 15:將 CheckBox 置中Discontinued

接下來,將 ValidationSummary 控制項新增至頁面,並將其 屬性設定為 true ,並將其 ShowSummary 屬性設定ShowMessageBoxfalse。 同時新增按鈕 Web 控制件,按兩下時,將會更新使用者的變更。 具體來說,新增兩個 Button Web 控件,一個在 GridView 上方,另一個在下方,將這兩個控件 Text 屬性設定為 [更新產品]。

因為 GridView 的編輯介面是在 TemplateFields ItemTemplate 中定義,所以 s EditItemTemplate 是多餘的,而且可能會遭到刪除。

進行上述格式設定變更之後,新增 Button 控制項並移除不必要的 EditItemTemplate ,頁面的宣告式語法看起來應該如下所示:

<p>
    <asp:Button ID="UpdateAllProducts1" runat="server" Text="Update Products" />
</p>
<p>
    <asp:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False" 
        DataKeyNames="ProductID" DataSourceID="ProductsDataSource" 
        AllowPaging="True" AllowSorting="True">
        <Columns>
            <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
                <ItemTemplate>
                    <asp:TextBox ID="ProductName" runat="server" 
                        Text='<%# Bind("ProductName") %>'></asp:TextBox>
                    <asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
                        ControlToValidate="ProductName"
                        ErrorMessage="You must provide the product's name." 
                        runat="server">*</asp:RequiredFieldValidator>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Category" 
                SortExpression="CategoryName">
                <ItemTemplate>
                    <asp:DropDownList ID="Categories" runat="server" 
                        AppendDataBoundItems="True" 
                        DataSourceID="CategoriesDataSource"
                        DataTextField="CategoryName" 
                        DataValueField="CategoryID" 
                        SelectedValue='<%# Bind("CategoryID") %>'>
                        <asp:ListItem>-- Select One --</asp:ListItem>
                    </asp:DropDownList>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Price" 
                SortExpression="UnitPrice">
                <ItemTemplate>
                    $<asp:TextBox ID="UnitPrice" runat="server" Columns="8" 
                        Text='<%# Bind("UnitPrice", "{0:N}") %>'></asp:TextBox>
                    <asp:CompareValidator ID="CompareValidator1" runat="server" 
                        ControlToValidate="UnitPrice"
                        ErrorMessage="You must enter a valid currency value. 
                                      Please omit any currency symbols."
                        Operator="GreaterThanEqual" Type="Currency" 
                        ValueToCompare="0">*</asp:CompareValidator>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
                <ItemTemplate>
                    <asp:CheckBox ID="Discontinued" runat="server" 
                        Checked='<%# Bind("Discontinued") %>' />
                </ItemTemplate>
                <ItemStyle HorizontalAlign="Center" />
            </asp:TemplateField>
        </Columns>
    </asp:GridView>
</p>
<p>
    <asp:Button ID="UpdateAllProducts2" runat="server" Text="Update Products" />
    <asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
        OldValuesParameterFormatString="original_{0}"
        SelectMethod="GetProducts" TypeName="ProductsBLL">
    </asp:ObjectDataSource>
    <asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
        OldValuesParameterFormatString="original_{0}"
        SelectMethod="GetCategories" TypeName="CategoriesBLL">
    </asp:ObjectDataSource>
    <asp:ValidationSummary ID="ValidationSummary1" runat="server" 
        ShowMessageBox="True" ShowSummary="False" />
</p>

圖 16 顯示此頁面,在新增按鈕 Web 控件之後透過瀏覽器檢視,以及所做的格式設定變更。

頁面現在包含兩個更新產品按鈕

圖 16:頁面現在包含兩個更新產品按鈕, (按兩下即可檢視完整大小的映像)

步驟 5:更新產品

當使用者瀏覽此頁面時,他們將會進行修改,然後按兩個 [更新產品] 按鈕的其中一個。 此時,我們需要以某種方式將每個數據列的使用者輸入值儲存到 ProductsDataTable 實例,然後將它傳遞至 BLL 方法,然後將該 ProductsDataTable 實例傳遞至 DAL s UpdateWithTransaction 方法。 UpdateWithTransaction我們在上一個教學課程中建立的方法,可確保變更批次會更新為不可部分完成的作業。

在 中BatchUpdate.aspx.cs建立名為 BatchUpdate 的方法,並新增下列程序代碼:

private void BatchUpdate()
{
    // Enumerate the GridView's Rows collection and create a ProductRow
    ProductsBLL productsAPI = new ProductsBLL();
    Northwind.ProductsDataTable products = productsAPI.GetProducts();
    foreach (GridViewRow gvRow in ProductsGrid.Rows)
    {
        // Find the ProductsRow instance in products that maps to gvRow
        int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
        Northwind.ProductsRow product = products.FindByProductID(productID);
        if (product != null)
        {
            // Programmatically access the form field elements in the 
            // current GridViewRow
            TextBox productName = (TextBox)gvRow.FindControl("ProductName");
            DropDownList categories = 
                (DropDownList)gvRow.FindControl("Categories");
            TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
            CheckBox discontinued = 
                (CheckBox)gvRow.FindControl("Discontinued");
            // Assign the user-entered values to the current ProductRow
            product.ProductName = productName.Text.Trim();
            if (categories.SelectedIndex == 0) 
                product.SetCategoryIDNull(); 
            else 
                product.CategoryID = Convert.ToInt32(categories.SelectedValue);
            if (unitPrice.Text.Trim().Length == 0) 
                product.SetUnitPriceNull(); 
            else 
                product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
            product.Discontinued = discontinued.Checked;
        }
    }
    // Now have the BLL update the products data using a transaction
    productsAPI.UpdateWithTransaction(products);
}

這個方法一開始會透過呼叫 BLL s GetProducts 方法,將所有產品傳回 ProductsDataTable 。 然後, ProductGrid 它會列舉 GridView 的 Rows 集合。 集合Rows包含 GridViewRow GridView 中顯示的每個資料列實例。 因為我們每頁最多顯示10個數據列,所以 GridView 集合 Rows 將不會有超過10個專案。

針對每個資料列,ProductID會從DataKeys集合擷取 ,並從中選取ProductsDataTable適當的 ProductsRow 。 會以程式設計方式參考四個 TemplateField 輸入控件,以及指派給 ProductsRow 實例屬性的值。 在每個 GridView 數據列的值都用來更新 ProductsDataTable之後,它會傳遞至 BLL s UpdateWithTransaction 方法,如我們在上一個教學課程中所見,只要向下呼叫 DAL s UpdateWithTransaction 方法即可。

本教學課程所使用的批次更新演算法會更新 對應至 GridView 中某個數據列的 中的每個 ProductsDataTable 數據列,不論產品資訊是否已變更。 雖然這類盲目更新通常不是效能問題,但如果您重新稽核資料庫數據表的變更,可能會導致多餘的記錄。 回到執行批次 匯報 教學課程中,我們探索了具有 DataList 的批次更新介面,並新增了只會更新用戶實際修改之記錄的程序代碼。 如有需要,請隨意使用執行 Batch 匯報 中的技術來更新本教學課程中的程序代碼。

注意

透過其智慧標記將數據源系結至 GridView 時,Visual Studio 會自動將數據源的主鍵值指派給 GridView s 屬性 (s DataKeyNames) 。 如果您未透過 GridView 智慧標記將 ObjectDataSource 系結至 GridView,如步驟 1 所述,則必須手動將 GridView s DataKeyNames 屬性設定為 ProductID,才能透過DataKeys集合存取ProductID每個數據列的值。

中使用的 BatchUpdate 程式代碼類似於 BLL 方法 UpdateProduct 中使用的程式代碼,主要差異在於方法中 UpdateProduct 只有單 ProductRow 一實例是從架構擷取。 指派 屬性ProductRow的程式代碼在 中的BatchUpdate方法與 迴圈內的foreach程式代碼之間UpdateProducts相同,如同整體模式。

若要完成本教學課程,我們需要在 BatchUpdate 按兩下其中一個 [更新產品] 按鈕時叫用 方法。 為 Click 這兩個 Button 控件的事件建立事件處理程式,並在事件處理程式中新增下列程式代碼:

BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message", 
    "alert('The products have been updated.');", true);

首先呼叫 BatchUpdate。 接下來, ClientScript property 會用來插入 JavaScript,以顯示讀取產品的消息框。

請花一分鐘來測試此程序代碼。 瀏覽 BatchUpdate.aspx 瀏覽器、編輯數列,然後按下其中一個 [更新產品] 按鈕。 假設沒有輸入驗證錯誤,您應該會看到一個消息框,其中讀取產品已更新。 若要確認更新的不可部分完成性,請考慮新增隨機 CHECK 條件約束,就像不允許 UnitPrice 1234.56 的值一樣。 然後,編輯 BatchUpdate.aspx數筆記錄,請務必將其中一個產品 UnitPrice 值設定為禁止值, ( 1234.56 ) 。 當單擊 [更新產品] 時,該批次作業期間的其他變更回復至其原始值時,這應該會產生錯誤。

替代BatchUpdate方法

BatchUpdate我們剛才檢查的方法會從 BLL GetProducts 方法擷取所有產品,然後只更新出現在 GridView 中的記錄。 如果 GridView 未使用分頁,但如果是,則此方法很理想,但可能會有數百、千或數千個產品,但 GridView 中只有十個數據列。 在這種情況下,只從資料庫取得所有產品以修改 10 個產品就小於理想。

針對這些類型的情況,請考慮改用下列 BatchUpdateAlternate 方法:

private void BatchUpdateAlternate()
{
    // Enumerate the GridView's Rows collection and create a ProductRow
    ProductsBLL productsAPI = new ProductsBLL();
    Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
    foreach (GridViewRow gvRow in ProductsGrid.Rows)
    {
        // Create a new ProductRow instance
        int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
        
        Northwind.ProductsDataTable currentProductDataTable = 
            productsAPI.GetProductByProductID(productID);
        if (currentProductDataTable.Rows.Count > 0)
        {
            Northwind.ProductsRow product = currentProductDataTable[0];
            // Programmatically access the form field elements in the 
            // current GridViewRow
            TextBox productName = (TextBox)gvRow.FindControl("ProductName");
            DropDownList categories = 
                (DropDownList)gvRow.FindControl("Categories");
            TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
            CheckBox discontinued = 
                (CheckBox)gvRow.FindControl("Discontinued");
            // Assign the user-entered values to the current ProductRow
            product.ProductName = productName.Text.Trim();
            if (categories.SelectedIndex == 0) 
                product.SetCategoryIDNull(); 
            else 
                product.CategoryID = Convert.ToInt32(categories.SelectedValue);
            if (unitPrice.Text.Trim().Length == 0) 
                product.SetUnitPriceNull(); 
            else 
                product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
            product.Discontinued = discontinued.Checked;
            // Import the ProductRow into the products DataTable
            products.ImportRow(product);
        }
    }
    // Now have the BLL update the products data using a transaction
    productsAPI.UpdateProductsWithTransaction(products);
}

BatchMethodAlternate從建立名為 products的新空白ProductsDataTable開始。 然後,它會逐步執行 GridView 的 Rows 集合,並針對每個數據列,使用 BLL s GetProductByProductID(productID) 方法取得特定產品資訊。 擷取ProductsRow的實例的屬性更新方式BatchUpdate與 相同,但在更新數據列之後,會透過 DataTable s ImportRow(DataRow) 方法將它匯入 。products``ProductsDataTable

foreach迴圈完成之後,products會針對 GridView 中的每個數據列包含一個ProductsRow實例。 由於每個 ProductsRow 實例都已新增至 products (,而不是更新) ,如果我們將它盲目傳遞至 UpdateWithTransaction 方法 ProductsTableAdapter ,則會嘗試將每筆記錄插入資料庫中。 相反地,我們需要指定每個數據列都已修改, (未新增) 。

這可以藉由將新的方法新增至名為 UpdateProductsWithTransaction的 BLL 來完成。 UpdateProductsWithTransaction如下所示,將 RowStateProductsDataTable每個ProductsRow實例的 設定為 Modified ,然後將 傳遞ProductsDataTable至 DAL s UpdateWithTransaction 方法。

public int UpdateProductsWithTransaction(Northwind.ProductsDataTable products)
{
    // Mark each product as Modified
    products.AcceptChanges();
    foreach (Northwind.ProductsRow product in products)
        product.SetModified();
    // Update the data via a transaction
    return UpdateWithTransaction(products);
}

摘要

GridView 提供內建的個別數據列編輯功能,但不支援建立完全可編輯的介面。 如本教學課程中所見,這類介面可能,但需要一些工作。 若要建立可編輯每個數據列的 GridView,我們需要將 GridView 欄位轉換成 TemplateFields,並在 內定義編輯介面 ItemTemplate 。 此外,必須將 [全部更新] 類型按鈕 Web 控件新增至頁面,與 GridView 分開。 這些 Buttons Click 事件處理程式需要列舉 GridView 的 Rows 集合、將變更儲存在 中 ProductsDataTable,並將更新的資訊傳遞至適當的 BLL 方法。

在下一個教學課程中,我們將瞭解如何建立用於批次刪除的介面。 特別是,每個 GridView 數據列都會包含一個複選框,而不是 [全部更新類型] 按鈕,我們會有 [刪除選取的數據列] 按鈕。

快樂的程序設計!

關於作者

Scott Mitchell 是七份 ASP/ASP.NET 書籍的作者,以及 1998 年以來與 Microsoft Web 技術合作的 4GuysFromRolla.com 作者。 Scott 是獨立顧問、訓練員和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格來連線到 ,您可以在 找到http://ScottOnWriting.NET

特別感謝

本教學課程系列是由許多實用的檢閱者檢閱。 本教學課程的首席檢閱者是 Teresa Murphy 和 David Suru。 有興趣檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行 mitchell@4GuysFromRolla.com放在 。