Dela via


Utföra Batch-uppdateringar (VB)

av Scott Mitchell

Ladda ned PDF

Lär dig hur du skapar en fullständigt redigerbar datalista där alla dess objekt är i redigeringsläge och vars värden kan sparas genom att klicka på knappen "Uppdatera alla" på sidan.

Inledning

I föregående självstudie undersökte vi hur du skapar en datalista på objektnivå. Precis som det redigerbara standardobjektet GridView innehöll varje objekt i DataList en redigeringsknapp som, när det klickades, skulle göra objektet redigerbart. Även om den här redigeringen på objektnivå fungerar bra för data som bara uppdateras ibland, kräver vissa användningsfall att användaren redigerar många poster. Om en användare behöver redigera dussintals poster och tvingas klicka på Redigera, göra sina ändringar och klicka på Uppdatera för var och en, kan mängden klick hindra hennes produktivitet. I sådana situationer är ett bättre alternativ att tillhandahålla en fullständigt redigerbar DataList, en där alla dess objekt är i redigeringsläge och vars värden kan redigeras genom att klicka på knappen Uppdatera alla på sidan (se bild 1).

Varje objekt i en fullständigt redigerbar datalista kan ändras

Bild 1: Varje objekt i en fullständigt redigerbar datalista kan ändras (Klicka om du vill visa en bild i full storlek)

I den här självstudien ska vi undersöka hur du gör det möjligt för användare att uppdatera leverantörsadressinformation med hjälp av en fullständigt redigerbar datalista.

Steg 1: Skapa det redigerbara användargränssnittet i DataList s ItemTemplate

I föregående självstudie, där vi skapar en redigerbar datalista på standardnivå, använde vi två mallar:

  • ItemTemplate innehöll det skrivskyddade användargränssnittet (etikettwebbkontrollerna för att visa varje produkts namn och pris).
  • EditItemTemplate innehöll användargränssnittet för redigeringsläget (de två TextBox-webbkontrollerna).

Egenskapen DataList avgör EditItemIndex vad DataListItem (om någon) återges med hjälp av EditItemTemplate. I synnerhet, den DataListItem vars ItemIndex-värde matchar DataLists EditItemIndex-egenskap renderas med hjälp av EditItemTemplate. Den här modellen fungerar bra när endast ett objekt kan redigeras i taget, men faller isär när du skapar en fullständigt redigerbar datalista.

För en fullständigt redigerbar DataList önskar vi att allaDataListItem s återges med hjälp av det redigerbara gränssnittet. Det enklaste sättet att åstadkomma detta är att definiera det redigerbara gränssnittet i ItemTemplate. För att ändra leverantörens adressinformation innehåller det redigerbara gränssnittet leverantörsnamnet som text och sedan Textrutor för värdena adress, stad och land/region.

Börja med att öppna sidan BatchUpdate.aspx , lägg till en DataList-kontroll och ange dess ID egenskap till Suppliers. Från datalistans smarta tagg väljer du att lägga till en ny ObjectDataSource-kontroll med namnet SuppliersDataSource.

Skapa en ny ObjectDataSource med namnet SuppliersDataSource

Bild 2: Skapa en ny ObjectDataSource med namnet SuppliersDataSource (Klicka om du vill visa en bild i full storlek)

Konfigurera ObjectDataSource för att hämta data med hjälp av SuppliersBLL klassens GetSuppliers() -metod (se bild 3). Precis som i föregående självstudie, i stället för att uppdatera leverantörsinformationen via ObjectDataSource, arbetar vi direkt med affärslogiklagret. Ange därför listrutan till (Ingen) på fliken UPPDATERA (se bild 4).

Hämta leverantörsinformation med metoden GetSuppliers()

Bild 3: Hämta leverantörsinformation med hjälp av GetSuppliers() metoden (Klicka om du vill visa en bild i full storlek)

Ange Drop-Down-listan till (Ingen) på fliken UPPDATERA

Bild 4: Ange Drop-Down-listan till (Ingen) på fliken UPPDATERA (Klicka om du vill visa en bild i full storlek)

När du har slutfört guiden genererar Visual Studio automatiskt DataList ItemTemplate som visar varje datafält som returneras av datakällan i en etikettwebbkontroll. Vi måste ändra den här mallen så att den tillhandahåller redigeringsgränssnittet i stället. ItemTemplate Kan anpassas via designern med alternativet Redigera mallar från datalistans smarta tagg eller direkt via deklarativ syntax.

Ta en stund att skapa ett redigeringsgränssnitt som visar leverantörens namn som text, men som innehåller Textrutor för leverantörens adress, stad och land/region-värden. När du har gjort dessa ändringar bör sidans deklarativa syntax se ut ungefär så här:

<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>

Anmärkning

Precis som i föregående självstudie måste datalistan i den här självstudien ha sitt visningstillstånd aktiverat.

ItemTemplate Jag använder två nya CSS-klasser, SupplierPropertyLabel och SupplierPropertyValue, som har lagts till i klassen Styles.css och konfigurerats för att använda samma formatinställningar som CSS-klasserna ProductPropertyLabel och ProductPropertyValue.

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

När du har gjort dessa ändringar går du till den här sidan via en webbläsare. Som bild 5 visar visar varje DataList-objekt leverantörsnamnet som text och använder Textrutor för att visa adressen, staden och landet/regionen.

Varje leverantör i datalistan kan redigeras

Bild 5: Varje leverantör i datalistan kan redigeras (Klicka om du vill visa en bild i full storlek)

Steg 2: Lägga till knappen Uppdatera alla

Varje leverantör i bild 5 har sina adress-, stads- och lands-/regionfält som visas i en textruta, men det finns för närvarande ingen uppdateringsknapp tillgänglig. I stället för att ha en uppdateringsknapp per objekt, med fullständigt redigerbara datalistor, finns det vanligtvis en enda uppdatera alla-knapp på sidan som uppdaterar alla poster i datalistan när du klickar på den. I den här självstudien ska vi lägga till två Uppdatera alla-knappar – en överst på sidan och en längst ned (även om du klickar på någon av knapparna får du samma effekt).

Börja med att lägga till en knappwebbkontroll ovanför DataList och ange dess ID egenskap till UpdateAll1. Lägg sedan till den andra knappwebbkontrollen under DataList och ange dess ID till UpdateAll2. Text Ange egenskaperna för de två knapparna till Uppdatera alla. Slutligen skapar du händelsehanterare för båda knapparnas Click händelser. I stället för att duplicera uppdateringslogik i var och en av händelsehanterarna ska vi omstrukturera logiken till en tredje metod, UpdateAllSupplierAddressesoch låta händelsehanterarna bara anropa den tredje metoden.

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

Bild 6 visar sidan när knapparna Uppdatera alla har lagts till.

Två uppdatera alla knappar har lagts till på sidan

Bild 6: Två uppdatera alla knappar har lagts till på sidan (klicka om du vill visa en bild i full storlek)

Steg 3: Uppdatera all information om leverantörernas adress

Med alla DataList-objekt som visar redigeringsgränssnittet och med tillägg av knapparna Uppdatera alla, är allt som återstår att skriva koden för att utföra batchuppdateringen. Mer specifikt behöver vi loopa igenom DataList-objekten SuppliersBLL och anropa klassens UpdateSupplierAddress metod för var och en.

Samlingen av DataListItem instanser som utgör DataList kan nås via DataLists Items egenskap. Med en referens till DataListItem kan vi hämta motsvarande SupplierID från DataKeys-samlingen och programmeringsmässigt referera till webbkontrollerna för TextBox i ItemTemplate, som följande kod illustrerar:

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

När användaren klickar på någon av knapparna UpdateAllSupplierAddresses Uppdatera alla itererar metoden genom var och en DataListItem i Suppliers DataList och anropar SuppliersBLL klassens UpdateSupplierAddress metod och skickar motsvarande värden. Ett icke-angivet värde för adress, stad eller land/region-pass är värdet Nothing till UpdateSupplierAddress (i stället för en tom sträng), vilket resulterar i en databas NULL för de underliggande postfälten.

Anmärkning

Som en förbättring kanske du vill lägga till en webbkontroll för statusetiketter på sidan som ger ett bekräftelsemeddelande när batchuppdateringen har utförts.

Uppdaterar endast de adresser som har ändrats

Den batchuppdateringsalgoritmen som används för den här handledningen anropar metoden UpdateSupplierAddress för varje leverantör i DataList, oavsett om deras adressinformation har ändrats. Även om sådana blinda uppdateringar vanligtvis inte är ett prestandaproblem kan de leda till överflödiga poster om du granskar ändringar i databastabellen. Om du till exempel använder utlösare för att registrera alla UPDATE i Suppliers tabellen till en granskningstabell, skapas varje gång en användare klickar på knappen Uppdatera alla en ny granskningspost för varje leverantör i systemet, oavsett om användaren har gjort några ändringar.

Klasserna ADO.NET DataTable och DataAdapter är utformade för att stödja batchuppdateringar där endast ändrade, borttagna och nya poster resulterar i databaskommunikation. Varje rad i DataTable har en RowState egenskap som anger om raden har lagts till i DataTable, tagits bort från den, ändrats eller förblir oförändrad. När en DataTable först fylls i markeras alla rader oförändrade. Om du ändrar värdet för någon av radkolumnerna markeras raden som ändrad.

SuppliersBLL I klassen uppdaterar vi den angivna leverantörens adressinformation genom att först läsa in den enskilda leverantörsposten i en SuppliersDataTable och sedan ange kolumnvärdena Address, Cityoch Country med hjälp av följande kod:

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

Den här koden tilldelar naivt de anförda värdena för adress, stad och land/region till SuppliersRow i SuppliersDataTable oavsett om värdena har ändrats eller inte. Dessa ändringar gör att egenskapen SuppliersRows RowState markeras som ändrad. När metoden Data Access Layer anropas Update ser den att SupplierRow har ändrats och skickar därför ett UPDATE kommando till databasen.

Anta dock att vi har lagt till kod i den här metoden för att endast tilldela de införda värdena för adress, stad och land/region om de skiljer sig från de SuppliersRow befintliga värdena. Om adressen, orten och landet/regionen är samma som befintliga data, görs inga ändringar och SupplierRow s RowState lämnas markerade som oförändrade. Nettoresultatet är att när DAL-metoden anropas Update görs inget databasanrop eftersom inte SuppliersRow har ändrats.

Om du vill genomföra den här ändringen ersätter du de instruktioner som blindt tilldelar de införda adress-, stads- och lands-/regionvärdena med följande kod:

' 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

Med den här tillagda koden skickar DAL-metoden Update en UPDATE -instruktion till databasen för endast de poster vars adressrelaterade värden har ändrats.

Alternativt kan vi hålla reda på om det finns några skillnader mellan de skickade adressfälten och databasdata och, om det inte finns några, helt enkelt kringgå anropet till DAL-metoden Update . Den här metoden fungerar bra om du använder DB-direktmetoden, eftersom DB-direktmetoden inte får en SuppliersRow-instans vars RowState kan kontrolleras för att avgöra om ett databasanrop verkligen behövs.

Anmärkning

Varje gång metoden UpdateSupplierAddress anropas görs ett anrop till databasen för att hämta information om den uppdaterade posten. Om det sedan finns några ändringar i data görs ytterligare ett anrop till databasen för att uppdatera tabellraden. Det här arbetsflödet kan optimeras genom att skapa en UpdateSupplierAddress metodöverbelastning som accepterar en EmployeesDataTable instans som har alla ändringar från BatchUpdate.aspx sidan. Sedan kan det göra ett anrop till databasen för att hämta alla poster från tabellen Suppliers. De två resultatuppsättningarna kan sedan räknas upp och endast de poster där ändringar har gjorts kan uppdateras.

Sammanfattning

I den här självstudien såg vi hur du skapar en fullständigt redigerbar datalista så att en användare snabbt kan ändra adressinformationen för flera leverantörer. Vi började med att definiera redigeringsgränssnittet som en TextBox-webbkontroll för leverantörens adress-, stads- och lands-/regionvärden i DataList s ItemTemplate. Därefter har vi lagt till Uppdatera alla knappar ovanför och under DataList. När en användare har gjort sina ändringar och klickat på någon av knapparna DataListItem Uppdatera alla räknas s upp och ett anrop till SuppliersBLL klassens UpdateSupplierAddress -metod görs.

Lycka till med programmerandet!

Om författaren

Scott Mitchell, författare till sju ASP/ASP.NET-böcker och grundare av 4GuysFromRolla.com, har arbetat med Microsofts webbtekniker sedan 1998. Scott arbetar som oberoende konsult, tränare och författare. Hans senaste bok är Sams Teach Yourself ASP.NET 2.0 på 24 timmar. Han kan nås på mitchell@4GuysFromRolla.com.

Särskilt tack till

Den här självstudieserien granskades av många användbara granskare. Huvudgranskare för den här handledningen var Zack Jones och Ken Pespisa. Vill du granska mina kommande MSDN-artiklar? Om så är fallet, hör av dig på mitchell@4GuysFromRolla.com.