共用方式為


執行批次更新 (VB)

由斯科特· 米切爾

下載 PDF

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

簡介

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

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

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

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

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

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

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

DataList 的 EditItemIndex 屬性會指定使用 EditItemTemplate轉譯的內容DataListItem(如果有的話)。 特別是, DataListItemItemIndex 值符合 DataList 屬性的 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 更新供應商資訊,而是直接使用商業規則層。 因此,將 [UPDATE] 索引標籤中的下拉式清單設定為 [無] (請參閱圖 4)。

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

圖 3:使用 方法擷 GetSuppliers() 取供貨商資訊 (按兩下以檢視完整大小的影像

將 [更新] 索引標籤中的下拉式清單設定為 [無]

圖 4:將 [更新] 索引標籤中的下拉式清單設定為 [無] (按兩下以檢視完整大小的影像

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

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

<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 必須啟用其檢視狀態。

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

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

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

DataList 中的每個供應商都是可編輯的

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

步驟 2:新增 [更新所有] 按鈕

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

首先,在 DataList 上方新增 Button Web 控制件,並將其 屬性設定 IDUpdateAll1。 接下來,在 DataList 底下新增第二個 Button Web 控件,並將其 ID 設定為 UpdateAll2Text將兩個按鈕的屬性設定為 [全部更新]。 最後,為這兩個 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 方法,並傳入對應的值。 位址、城市或國家/地區傳遞的非輸入值是 Nothing 的值( UpdateSupplierAddress 而不是空白字串),這會導致 NULL 基礎記錄字段的資料庫。

注意

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

只更新已修改的位址

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

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

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

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

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

不過,假設我們已將程式代碼新增至這個方法,只有在傳入的位址、城市和國家/地區值與 SuppliersRow 現有值不同時,才會指派傳入的位址、城市和國家/地區值。 如果位址、城市和國家/地區與現有資料相同,則不會進行任何變更,且會 SupplierRow 保留標示為未變更的 RowState 。 淨結果是呼叫 DAL 方法 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 的 Update 方法只會針對地址相關值已變更的記錄,將語句傳送 UPDATE 至資料庫。

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

注意

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

摘要

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

快樂的程序設計!

關於作者

斯科特·米切爾,七本 ASP/ASP.NET 書籍和 4GuysFromRolla.com 創始人的作者,自1998年以來一直與Microsoft Web 技術合作。 斯科特擔任獨立顧問、教練和作家。 他的最新書是 山姆斯在24小時內 ASP.NET 2.0。 他可以到達 mitchell@4GuysFromRolla.com, 或通過他的博客,可以在 找到 http://ScottOnWriting.NET

特別感謝

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