共用方式為


執行批次更新 (VB)

作者:Scott Mitchell

下載 PDF

瞭解如何建立完全可編輯的 DataList,其中其所有專案都處於編輯模式,且其值可以透過按兩下頁面上的 [全部更新] 按鈕來儲存。

簡介

上述教學課程 中,我們檢查了如何建立專案層級的 DataList。 就像標準可編輯的 GridView 一樣,DataList 中的每個專案都包含 [編輯] 按鈕,按兩下時,專案可以編輯。 雖然此專案層級編輯適用於偶爾只會更新的數據,但某些使用案例需要使用者編輯許多記錄。 如果使用者需要編輯數十筆記錄,並強制按兩下 [編輯],進行其變更,然後按兩下每一筆記錄的 [更新],按兩下次數可能會降低其生產力。 在這種情況下,更好的選項是提供完全可編輯的 DataList,其中 其所有 專案都處於編輯模式,而且按下頁面上的 [全部更新] 按鈕即可編輯其值, (請參閱圖 1) 。

可以修改完全編輯 DataList 中的每個專案

圖 1:可完整編輯 DataList 中的每個專案都可以修改 (按兩下即可檢視完整大小的影像)

在本教學課程中,我們將探討如何讓使用者使用完全可編輯的 DataList 來更新供應商地址資訊。

步驟 1:在 DataList s ItemTemplate 中建立可編輯的使用者介面

在上述教學課程中,我們會在其中建立標準、專案層級可編輯的 DataList,我們使用兩個範本:

  • ItemTemplate 包含唯讀使用者介面, (標籤 Web 控件,以顯示每個產品名稱和價格) 。
  • EditItemTemplate 包含編輯模式使用者介面, (兩個 TextBox Web 控件) 。

DataList s EditItemIndex 屬性會指定 DataListItem 如果使用 轉譯任何) , EditItemTemplate (。 特別是, DataListItemItemIndex 值符合 DataList s EditItemIndex 屬性的 會使用 EditItemTemplate轉譯。 當一次只能編輯一個專案,但建立可完全編輯的 DataList 時,此模型可正常運作。

針對完全可編輯的 DataList,我們想要使用可編輯的介面來轉譯 所有DataListItem 。 完成此作業的最簡單方式是在 中定義可編輯的 ItemTemplate介面。 若要修改供應商地址資訊,可編輯的介面包含供應商名稱做為文字,然後是位址、城市和國家/地區值的 TextBoxes。

從開啟頁面開始 BatchUpdate.aspx ,新增 DataList 控制項,並將其屬性設定 IDSuppliers。 從 DataList 的智慧標記中,選擇新增名為 SuppliersDataSource的新 ObjectDataSource 控件。

建立名為 SuppliersDataSource 的新 ObjectDataSource

圖 2:建立名為 SuppliersDataSource 的新 ObjectDataSource (按兩下即可檢視大小完整的映射)

設定 ObjectDataSource 以使用 SuppliersBLL 類別 s GetSuppliers() 方法擷取數據 (請參閱圖 3) 。 如同上述教學課程,我們不會透過 ObjectDataSource 更新供應商資訊,而是直接使用商業規則層。 因此,將下拉式清單設定為 [更新] 索引標籤中的 ([無) ], (請參閱圖 4) 。

使用 GetSuppliers () 方法擷取供應商資訊

圖 3:使用 GetSuppliers() 方法擷取供貨商資訊 (按兩下以檢視全尺寸影像)

將 [Drop-Down 列表] 設定為 [更新] 索引標籤中的 [無 (])

圖 4:將 [Drop-Down 列表] 設定 (為 [更新] 索引卷標的 [無) ] (按兩下即可檢視完整大小的映像)

完成精靈之後,Visual Studio 會自動產生 DataList s ItemTemplate 以顯示卷標 Web 控件中數據源所傳回的每個數據欄位。 我們需要修改此範本,使其改為提供編輯介面。 ItemTemplate可以使用 DataList 智慧標記中的 [編輯範本] 選項,或直接透過宣告式語法,透過 Designer 自定義 。

請花點時間建立編輯介面,將供貨商的名稱顯示為文字,但包含供應商位址、城市和國家/地區值的 TextBox。 進行這些變更之後,頁面的宣告式語法看起來應該如下所示:

<asp:DataList ID="Suppliers" runat="server" DataKeyField="SupplierID"
    DataSourceID="SuppliersDataSource">
    <ItemTemplate>
        <h4><asp:Label ID="CompanyNameLabel" runat="server"
            Text='<%# Eval("CompanyName") %>' /></h4>
        <table border="0">
            <tr>
                <td class="SupplierPropertyLabel">Address:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Address" runat="server"
                        Text='<%# Eval("Address") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">City:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="City" runat="server"
                        Text='<%# Eval("City") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">Country:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Country" runat="server"
                        Text='<%# Eval("Country") %>' />
                </td>
            </tr>
        </table>
        <br />
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
</asp:ObjectDataSource>

注意

如同上述教學課程,本教學課程中的 DataList 必須啟用其檢視狀態。

ItemTemplate我使用的是兩個新的 CSS 類別和 SupplierPropertyValueSupplierPropertyLabel這些類別已新增至 Styles.css 類別,並設定為使用與 和 ProductPropertyValue CSS 類別相同的樣式設定ProductPropertyLabel

.ProductPropertyLabel, .SupplierPropertyLabel
{
    font-weight: bold;
    text-align: right;
}
.ProductPropertyValue, .SupplierPropertyValue
{
    padding-right: 35px;
}

進行這些變更之後,請透過瀏覽器瀏覽此頁面。 如圖 5 所示,每個 DataList 項目都會以文字顯示供應商名稱,並使用 TextBox 來顯示位址、城市和國家/地區。

DataList 中的每個供應商皆可編輯

圖 5:D ataList 中的每個供應商都是可編輯的 (按兩下即可檢視完整大小的影像)

步驟 2:新增 [全部更新] 按鈕

雖然圖 5 中的每個供應商都有其位址、城市和國家/地區字段顯示在 TextBox 中,但目前沒有可用的 [更新] 按鈕。 相較於每個專案的 [更新] 按鈕,具有完全可編輯的 DataLists,頁面上通常會有單一的 [全部更新] 按鈕,按兩下時,會更新 DataList 中的所有 記錄。 在本教學課程中,讓我們新增兩個 [全部更新] 按鈕 - 一個位於頁面頂端,另一個位於底部 (,雖然按兩下任一按鈕會有相同的效果) 。

首先,在 DataList 上方新增 Button Web 控制件,並將其 屬性設定 IDUpdateAll1。 接下來,在 DataList 底下新增第二個 Button Web 控件,並將其 ID 設定為 UpdateAll2。 將 Text 兩個按鈕的屬性設定為 [全部更新]。 最後,建立這兩個 Buttons Click 事件的事件處理程式。 讓我們將邏輯重構為第三個方法,而不要複製每個事件處理程式中的更新邏輯,而是將該邏輯重構為第三個方法, UpdateAllSupplierAddresses讓事件處理程式只叫用這個第三個方法。

Protected Sub UpdateAll1_Click(sender As Object, e As EventArgs) _
    Handles UpdateAll1.Click
    UpdateAllSupplierAddresses()
End Sub
Protected Sub UpdateAll2_Click(sender As Object, e As EventArgs) _
    Handles UpdateAll2.Click
    UpdateAllSupplierAddresses()
End Sub
Private Sub UpdateAllSupplierAddresses()
    ' TODO: Write code to update _all_ of the supplier addresses in the DataList
End Sub

圖 6 顯示新增 [全部更新] 按鈕之後的頁面。

已將兩個更新所有按鈕新增至頁面

圖 6:已將兩個更新所有按鈕新增至頁面 (按兩下以檢視大小完整的映像)

步驟 3:更新所有供應商地址資訊

當所有 DataList 項目顯示編輯介面,以及新增 [全部更新] 按鈕時,保留的所有項目都會撰寫程式代碼以執行批次更新。 具體而言,我們需要迴圈處理 DataList 的專案,併為每個專案呼叫 SuppliersBLL 類別 s UpdateSupplierAddress 方法。

可以透過 DataList 的 屬性存取 DataList 的Items實例集合DataListItem。 使用 的DataListItem參考,我們可以從DataKeys集合擷取對應的 SupplierID ,並以程式設計方式參考 中的 ItemTemplate TextBox Web 控制項,如下列程式碼所示:

Private Sub UpdateAllSupplierAddresses()
    ' Create an instance of the SuppliersBLL class
    Dim suppliersAPI As New SuppliersBLL()
    ' Iterate through the DataList's items
    For Each item As DataListItem In Suppliers.Items
        ' Get the supplierID from the DataKeys collection
        Dim supplierID As Integer = Convert.ToInt32(Suppliers.DataKeys(item.ItemIndex))
        ' Read in the user-entered values
        Dim address As TextBox = CType(item.FindControl("Address"), TextBox)
        Dim city As TextBox = CType(item.FindControl("City"), TextBox)
        Dim country As TextBox = CType(item.FindControl("Country"), TextBox)
        Dim addressValue As String = Nothing, _
            cityValue As String = Nothing, _
            countryValue As String = Nothing
        If address.Text.Trim().Length > 0 Then
            addressValue = address.Text.Trim()
        End If
        If city.Text.Trim().Length > 0 Then
            cityValue = city.Text.Trim()
        End If
        If country.Text.Trim().Length > 0 Then
            countryValue = country.Text.Trim()
        End If
        ' Call the SuppliersBLL class's UpdateSupplierAddress method
        suppliersAPI.UpdateSupplierAddress _
            (supplierID, addressValue, cityValue, countryValue)
    Next
End Sub

當使用者按兩下其中一個 [全部更新] 按鈕時, UpdateAllSupplierAddresses 方法會逐一查看 DataListItem DataList中的每個 Suppliers 按鈕,並呼叫 SuppliersBLL 類別 s UpdateSupplierAddress 方法,並傳入對應的值。 位址、城市或國家/地區傳遞的非輸入值是 (UpdateSupplierAddress 的值Nothing,而不是空白字串) ,這會導致基礎記錄字段的資料庫NULL

注意

為了增強功能,您可能會想要將狀態標籤 Web 控件新增至頁面,以在執行批次更新之後提供一些確認訊息。

僅更新已修改的位址

本教學課程所使用的批次更新演算法會針對 DataList 中的每個供應商呼叫UpdateSupplierAddress 方法,不論其地址資訊是否已變更。 雖然這類盲目更新通常不是效能問題,但如果您重新稽核資料庫數據表的變更,可能會導致多餘的記錄。 例如,如果您使用觸發程式將所有記錄 UPDATE 到稽核數據表, Suppliers 每當使用者按兩下 [全部更新] 按鈕時,系統中的每個供應商都會建立新的稽核記錄,不論使用者是否進行任何變更。

ADO.NET DataTable 和 DataAdapter 類別的設計目的是支援批次更新,其中只有修改、刪除和新記錄會導致任何資料庫通訊。 DataTable 中的每個數據列都有屬性RowState,指出數據列是否已新增至 DataTable、從其中刪除、修改或保持不變。 一開始填入 DataTable 時,所有數據列都會標示為未變更。 變更任何數據列數據列的值,會將數據列標示為已修改。

在類別中, SuppliersBLL 我們會先在單一供應商記錄中讀取至 SuppliersDataTable ,然後使用下列程式代碼來設定 AddressCity和數據 Country 行值,以更新指定的供應商地址資訊:

Public Function UpdateSupplierAddress _
    (supplierID As Integer, address As String, city As String, country As String) _
    As Boolean
    Dim suppliers As Northwind.SuppliersDataTable = _
        Adapter.GetSupplierBySupplierID(supplierID)
    If suppliers.Count = 0 Then
        ' no matching record found, return false
        Return False
    Else
        Dim supplier As Northwind.SuppliersRow = suppliers(0)
        If address Is Nothing Then
            supplier.SetAddressNull()
        Else
            supplier.Address = address
        End If
        If city Is Nothing Then
            supplier.SetCityNull()
        Else
            supplier.City = city
        End If
        If country Is Nothing Then
            supplier.SetCountryNull()
        Else
            supplier.Country = country
        End If
        ' Update the supplier Address-related information
        Dim rowsAffected As Integer = Adapter.Update(supplier)
        ' Return true if precisely one row was updated, otherwise false
        Return rowsAffected = 1
    End If
End Function

不論值是否已變更,此程式代碼都會將傳入的位址、城市和國家/地區值指派給 SuppliersRow 中的 SuppliersDataTable 。 這些修改會導致 SuppliersRow s RowState 屬性標示為已修改。 呼叫數據存取層的 Update 方法時,會看到 SupplierRow 已修改 ,因此會將命令傳送 UPDATE 至資料庫。

不過,想像一下,我們已將程式代碼新增至這個方法,以便只有在傳入的位址、城市和國家/地區值與 SuppliersRow 現有值不同時,才指派傳入的位址、城市和國家/地區值。 在位址、城市和國家/地區與現有資料相同的情況下,不會進行任何變更,且 SupplierRowRowState 會保留標示為未變更的 。 最終結果是呼叫 DAL s Update 方法時,不會進行任何資料庫呼叫,因為 SuppliersRow 尚未修改 。

若要制定這項變更,請使用下列程式代碼取代不小心指派傳入位址、城市和國家/地區值的語句:

' Only assign the values to the SupplierRow's column values if they differ
If address Is Nothing AndAlso Not supplier.IsAddressNull() Then
    supplier.SetAddressNull()
ElseIf (address IsNot Nothing AndAlso supplier.IsAddressNull) _
    OrElse (Not supplier.IsAddressNull() AndAlso _
                String.Compare(supplier.Address, address) <> 0) Then
    supplier.Address = address
End If
If city Is Nothing AndAlso Not supplier.IsCityNull() Then
    supplier.SetCityNull()
ElseIf (city IsNot Nothing AndAlso supplier.IsCityNull) _
    OrElse (Not supplier.IsCityNull() AndAlso _
                String.Compare(supplier.City, city) <> 0) Then
    supplier.City = city
End If
If country Is Nothing AndAlso Not supplier.IsCountryNull() Then
    supplier.SetCountryNull()
ElseIf (country IsNot Nothing AndAlso supplier.IsCountryNull) _
    OrElse (Not supplier.IsCountryNull() AndAlso _
                String.Compare(supplier.Country, country) <> 0) Then
    supplier.Country = country
End If

使用這個新增的程式代碼,DAL s Update 方法只會針對地址相關值已變更的記錄,將語句傳送 UPDATE 至資料庫。

或者,我們可以追蹤傳遞的位址字段與資料庫數據之間是否有任何差異,如果沒有任何,只要略過對 DAL s Update 方法的呼叫即可。 如果您使用 DB 直接方法,此方法會正常運作,因為 DB 直接方法並未傳遞 SuppliersRow 可檢查的實例 RowState ,以判斷是否實際需要資料庫呼叫。

注意

每次 UpdateSupplierAddress 叫用 方法時,都會呼叫資料庫以擷取更新記錄的相關信息。 然後,如果數據有任何變更,則會對資料庫進行另一次呼叫來更新數據表數據列。 建立方法多載,以接受EmployeesDataTable具有頁面所有變更的BatchUpdate.aspx實例,藉此優化UpdateSupplierAddress此工作流程。 然後,它可以對資料庫進行一次呼叫,以從 Suppliers 數據表取得所有記錄。 然後可以列舉這兩個結果集,而且只能更新發生變更的記錄。

摘要

在本教學課程中,我們已瞭解如何建立完全可編輯的 DataList,讓使用者快速修改多個供應商的地址資訊。 我們從定義 DataList s ItemTemplate中供應商位址、城市和國家/地區值的 TextBox Web 控制項編輯介面開始。 接下來,我們新增了 DataList 上方和下方的 [更新所有] 按鈕。 當使用者進行變更並按兩下其中一個 [全部更新] 按鈕之後,會 DataListItem 列舉 s,並 SuppliersBLL 呼叫 類別 s UpdateSupplierAddress 方法。

快樂的程序設計!

關於作者

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

特別感謝

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