Freigeben über


Aktualisieren in Batches (VB)

von Scott Mitchell

PDF herunterladen

Erfahren Sie, wie Sie mehrere Datenbankeinträge in einem einzigen Vorgang aktualisieren. In der Benutzeroberfläche erstellen wir eine GridView, in der jede Zeile bearbeitet werden kann. In der Datenzugriffsebene umschließen wir die mehreren Aktualisierungsvorgänge innerhalb einer Transaktion, um sicherzustellen, dass alle Updates erfolgreich sind oder alle Updates zurückgesetzt werden.

Einführung

Im vorherigen Lernprogramm haben wir erfahren, wie Sie die Datenzugriffsschicht erweitern, um Unterstützung für Datenbanktransaktionen hinzuzufügen. Datenbanktransaktionen garantieren, dass eine Reihe von Datenänderungsanweisungen als ein atomer Vorgang behandelt wird, wodurch sichergestellt wird, dass alle Änderungen fehlschlagen oder alle erfolgreich sind. Mit dieser low-level DAL-Funktionalität sind wir bereit, unsere Aufmerksamkeit auf die Erstellung von Batchdatenänderungsschnittstellen zu lenken.

In diesem Lernprogramm erstellen wir eine GridView, in der jede Zeile bearbeitet werden kann (siehe Abbildung 1). Da jede Zeile in der Bearbeitungsoberfläche gerendert wird, ist keine Spalte mit den Schaltflächen "Bearbeiten", "Aktualisieren" und "Abbrechen" erforderlich. Stattdessen gibt es auf der Seite zwei Schaltflächen "Produkte aktualisieren", die beim Klicken auf die GridView-Zeilen aufzählen und die Datenbank aktualisieren.

Jede Zeile in der GridView kann bearbeitet werden.

Abbildung 1: Jede Zeile in der GridView ist bearbeitbar (Zum Anzeigen des Bilds mit voller Größe klicken)

Los geht's!

Hinweis

Im Lernprogramm zum Ausführen von Batchaktualisierungen haben wir eine Batchbearbeitungsschnittstelle mit dem DataList-Steuerelement erstellt. Dieses Lernprogramm unterscheidet sich von der vorherigen, in der ein GridView verwendet wird, und die Batchaktualisierung wird im Rahmen einer Transaktion ausgeführt. Nach Abschluss dieses Lernprogramms empfehlen ich Ihnen, zum vorherigen Lernprogramm zurückzukehren und es zu aktualisieren, um die im vorherigen Lernprogramm hinzugefügte Datenbanktransaktionsfunktionalität zu verwenden.

Untersuchen der Schritte zum Bearbeiten aller GridView-Zeilen

Wie im Lernprogramm zum Einfügen, Aktualisieren und Löschen von Daten erläutert, bietet GridView integrierte Unterstützung für die Bearbeitung der zugrunde liegenden Daten pro Zeile. Intern stellt die GridView fest, welche Zeile über ihre EditIndex Eigenschaft bearbeitet werden kann. Da die GridView an die Datenquelle gebunden wird, überprüft sie jede Zeile, um festzustellen, ob der Index der Zeile dem Wert entspricht EditIndex. Wenn ja, werden die Zeilenfelder mithilfe ihrer Bearbeitungsschnittstellen gerendert. Bei BoundFields ist die Bearbeitungsschnittstelle ein TextBox-Objekt, dessen Text Eigenschaft dem Wert des durch die BoundField-Eigenschaft angegebenen Datenfelds DataField zugewiesen ist. Für TemplateFields wird die EditItemTemplate anstelle der ItemTemplate.

Erinnern Sie sich daran, dass der Bearbeitungsworkflow gestartet wird, wenn ein Benutzer auf die Schaltfläche "Bearbeiten" einer Zeile klickt. Dadurch wird ein Postback ausgelöst, die GridView-Eigenschaft EditIndex auf den Index der geklickten Zeile festgelegt und die Daten an das Raster neu gebunden. Wenn auf die Schaltfläche "Abbrechen" einer Zeile geklickt wird, wird beim Postback der EditIndex Wert auf einen Wert festgelegt, bevor -1 die Daten erneut an das Raster gebunden werden. Da die GridView-Zeilen mit der Indizierung bei Null beginnen, wirkt sich die Einstellung EditIndex auf -1 die Anzeige der GridView im schreibgeschützten Modus aus.

Die EditIndex Eigenschaft eignet sich gut für die Bearbeitung pro Zeile, ist aber nicht für die Batchbearbeitung konzipiert. Damit die gesamte GridView bearbeitbar ist, müssen wir jede Zeile mithilfe der Bearbeitungsschnittstelle rendern lassen. Am einfachsten können Sie dies erreichen, um zu erstellen, wo jedes bearbeitbare Feld als TemplateField implementiert wird, dessen Bearbeitungsschnittstelle in der ItemTemplate.

Im nächsten Schritt erstellen wir eine vollständig bearbeitbare GridView. In Schritt 1 erstellen wir zunächst gridView und seine ObjectDataSource und konvertieren dessen BoundFields und CheckBoxField in TemplateFields. In den Schritten 2 und 3 verschieben wir die Bearbeitungsschnittstellen von Den TemplateFields in ihre ItemTemplate BearbeitungsfelderEditItemTemplate.

Schritt 1: Anzeigen von Produktinformationen

Bevor wir uns gedanken über das Erstellen einer GridView machen, bei der Zeilen bearbeitbar sind, beginnen wir damit, einfach die Produktinformationen anzuzeigen. Öffnen Sie die BatchUpdate.aspx Seite im BatchData Ordner, und ziehen Sie eine GridView aus der Toolbox auf den Designer. Legen Sie die GridView-Objekte ID auf ProductsGrid das Smarttag fest und legen Sie sie fest, um sie an eine neue ObjectDataSource mit dem Namen ProductsDataSourcezu binden. Konfigurieren Sie objectDataSource so, dass sie die Daten aus der Methode der ProductsBLL Klasse abruft GetProducts .

Konfigurieren der ObjectDataSource für die Verwendung der ProductsBLL-Klasse

Abbildung 2: Konfigurieren der ObjectDataSource für die Verwendung der Klasse (Zum Anzeigen des ProductsBLL Bilds mit voller Größe klicken)

Abrufen der Produktdaten mithilfe der GetProducts-Methode

Abbildung 3: Abrufen der Produktdaten mithilfe der GetProducts Methode (Klicken, um das Bild in voller Größe anzuzeigen)

Wie die GridView sind die Änderungsfeatures von ObjectDataSource so konzipiert, dass sie pro Zeile funktionieren. Um eine Reihe von Datensätzen zu aktualisieren, müssen wir ein wenig Code in der CodeBehind-Klasse der ASP.NET Seite schreiben, die die Daten in batchet und an die BLL übergibt. Legen Sie daher die Dropdownlisten in den Registerkarten "ObjectDataSource" UPDATE, INSERT und DELETE auf (Keine) fest. Klicken Sie auf Fertig stellen, um den Assistenten abzuschließen.

Legen Sie die Dropdownlisten in den Registerkarten UPDATE, INSERT und DELETE auf (Keine) fest.

Abbildung 4: Festlegen der Dropdownlisten in den Registerkarten UPDATE, INSERT und DELETE auf (Keine) (Klicken, um das Bild in voller Größe anzuzeigen)

Nach Abschluss des Assistenten zum Konfigurieren von Datenquellen sollte das deklarative Markup von ObjectDataSource wie folgt aussehen:

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

Wenn Sie den Assistenten zum Konfigurieren der Datenquelle abschließen, erstellt Visual Studio auch BoundFields und ein CheckBoxField für die Produktdatenfelder in GridView. Lassen Sie uns in diesem Lernprogramm nur zulassen, dass der Benutzer den Produktnamen, die Kategorie, den Preis und den Status "Nicht mehr" anzeigen und bearbeiten kann. Entfernen Sie alle Felder, aber die ProductNameFelder , CategoryNameUnitPriceund Discontinued benennen Sie die HeaderText Eigenschaften der ersten drei Felder in "Produkt", "Kategorie" bzw. "Preis" um. Aktivieren Sie schließlich die Kontrollkästchen "Paging aktivieren" und "Sortierung aktivieren" im Smarttag "GridView".

An diesem Punkt verfügt gridView über drei BoundFields (ProductName, CategoryNameund UnitPrice) und ein CheckBoxField (Discontinued). Wir müssen diese vier Felder in TemplateFields konvertieren und dann die Bearbeitungsschnittstelle aus den TemplateFields EditItemTemplate in das ItemTemplateFeld verschieben.

Hinweis

Wir haben das Erstellen und Anpassen von TemplateFields im Lernprogramm zum Anpassen der Datenänderungsschnittstelle untersucht. Wir werden die Schritte zum Konvertieren von BoundFields und CheckBoxField in TemplateFields und die Definition ihrer Bearbeitungsschnittstellen in ihren ItemTemplate Feldern durchgehen, aber wenn Sie hängen bleiben oder eine Aktualisierung benötigen, zögern Sie nicht, auf dieses frühere Lernprogramm zu verweisen.

Klicken Sie im Smarttag "GridView" auf den Link "Spalten bearbeiten", um das Dialogfeld "Felder" zu öffnen. Wählen Sie als Nächstes jedes Feld aus, und klicken Sie auf das Feld in einen TemplateField-Link konvertieren.

Konvertieren der vorhandenen BoundFields- und CheckBoxField-Elemente in TemplateFields

Abbildung 5: Konvertieren der vorhandenen BoundFields- und CheckBoxField-Elemente in TemplateFields

Da es sich bei jedem Feld um ein TemplateField handelt, können wir die Bearbeitungsschnittstelle von S EditItemTemplate zu S ItemTemplate verschieben.

Schritt 2: Erstellen derProductNameUnitPrice Schnittstellen undDiscontinuedBearbeiten von Schnittstellen

Das Erstellen der ProductNameSchnittstellen und Discontinued UnitPriceBearbeitungsschnittstellen ist das Thema dieses Schritts und ist ziemlich unkompliziert, da jede Schnittstelle bereits in den TemplateField-Elementen EditItemTemplatedefiniert ist. Das Erstellen der CategoryName Bearbeitungsschnittstelle ist etwas komplexer, da wir eine DropDownList der entsprechenden Kategorien erstellen müssen. Diese Bearbeitungsschnittstelle CategoryName wird in Schritt 3 behandelt.

Beginnen wir mit dem ProductName TemplateField. Klicken Sie im Smarttag von GridView auf den Link "Vorlagen bearbeiten", und führen Sie einen Drilldown zum ProductName TemplateField s EditItemTemplatedurch. Wählen Sie das TextBox-Objekt aus, kopieren Sie es in die Zwischenablage, und fügen Sie es dann in das ProductName TemplateField s ItemTemplateein. Ändern Sie die TextBox-Eigenschaft ID in ProductName.

Fügen Sie als Nächstes ein RequiredFieldValidator hinzu ItemTemplate , um sicherzustellen, dass der Benutzer einen Wert für jeden Produktnamen bereitstellt. Legen Sie die ControlToValidate Eigenschaft auf "ProductName" fest, die ErrorMessage Eigenschaft auf "Sie" muss den Namen des Produkts angeben. und die Text Eigenschaft auf *. Nachdem Sie diese Ergänzungen zum ItemTemplateBildschirm vorgenommen haben, sollte Ihr Bildschirm ähnlich aussehen wie in Abbildung 6.

Das ProductName TemplateField enthält jetzt ein TextBox- und ein RequiredFieldValidator-Element.

Abbildung 6: Das ProductName TemplateField enthält jetzt ein TextBox- und ein RequiredFieldValidator -Objekt (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Beginnen Sie für die UnitPrice Bearbeitungsschnittstelle mit dem Kopieren des TextBox-Steuerelements aus dem EditItemTemplate Textfeld in die ItemTemplate. Platzieren Sie als Nächstes ein $ vor dem TextBox-Steuerelement, und legen Sie dessen ID Eigenschaft auf UnitPrice und seine Columns Eigenschaft auf 8 fest.

Fügen Sie außerdem einen CompareValidator zu den UnitPrice s ItemTemplate hinzu, um sicherzustellen, dass der vom Benutzer eingegebene Wert ein gültiger Währungswert ist, der größer oder gleich 0,00 $ ist. Legen Sie die Eigenschaft des Validators ControlToValidate auf "UnitPrice" fest, dessen ErrorMessage Eigenschaft auf "Sie" muss einen gültigen Währungswert eingeben. Geben Sie alle Währungssymbole aus., ihre Text Eigenschaft auf *, ihre Type Eigenschaft auf Currency, ihre Operator Eigenschaft auf GreaterThanEqual, und ihre ValueToCompare Eigenschaft auf 0 .

Fügen Sie einen CompareValidator hinzu, um sicherzustellen, dass der eingegebene Preis ein nicht negativer Währungswert ist.

Abbildung 7: Hinzufügen eines CompareValidator-Werts, um sicherzustellen, dass der eingegebene Preis ein nicht negativer Währungswert ist (Klicken Sie hier, um das Bild mit voller Größe anzuzeigen)

Für das Discontinued TemplateField können Sie das bereits in der ItemTemplateDatei definierte CheckBox-Steuerelement verwenden. Legen Sie den ID Wert einfach auf "Nicht eingestellt" und seine Enabled Eigenschaft auf True" fest.

Schritt 3: Erstellen derCategoryNameBearbeitungsschnittstelle

Die Bearbeitungsschnittstelle in TemplateFields CategoryName EditItemTemplate enthält ein TextBox-Objekt, das den Wert des CategoryName Datenfelds anzeigt. Wir müssen dies durch eine DropDownList ersetzen, die die möglichen Kategorien auflistet.

Hinweis

Das Lernprogramm zum Anpassen der Datenänderungsschnittstelle enthält eine ausführlichere und vollständige Erläuterung zum Anpassen einer Vorlage, um eine DropDownList im Gegensatz zu einem TextBox-Element einzuschließen. Während die hier aufgeführten Schritte abgeschlossen sind, werden sie sehr gut dargestellt. Ausführlichere Informationen zum Erstellen und Konfigurieren der Kategorien DropDownList finden Sie im Lernprogramm zum Anpassen des Datenänderungsschnittstellen-Lernprogramms .

Ziehen Sie ein DropDownList-Objekt aus der Toolbox auf das CategoryName TemplateField s ItemTemplate, und legen Sie ihn ID auf Categories. An diesem Punkt würden wir in der Regel die Datenquelle von DropDownLists über das Smarttag definieren, wodurch eine neue ObjectDataSource erstellt wird. Dadurch wird jedoch die ObjectDataSource innerhalb des ItemTemplateObjekts hinzugefügt, was zu einer ObjectDataSource-Instanz führt, die für jede GridView-Zeile erstellt wurde. Stattdessen erstellen wir die ObjectDataSource außerhalb der GridView s TemplateFields. Beenden Sie die Bearbeitung der Vorlage, und ziehen Sie eine ObjectDataSource aus der Toolbox auf den Designer unter der ProductsDataSource ObjectDataSource. Benennen Sie die neue ObjectDataSource CategoriesDataSource , und konfigurieren Sie sie für die Verwendung der CategoriesBLL Klassenmethode GetCategories .

Konfigurieren der ObjectDataSource für die Verwendung der CategoriesBLL-Klasse

Abbildung 8: Konfigurieren der ObjectDataSource für die Verwendung der CategoriesBLL Klasse (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Abrufen der Kategoriedaten mithilfe der GetCategories-Methode

Abbildung 9: Abrufen der Kategoriedaten mithilfe der GetCategories Methode (Klicken, um das Bild in voller Größe anzuzeigen)

Da diese ObjectDataSource nur zum Abrufen von Daten verwendet wird, legen Sie die Dropdownlisten in den Registerkarten UPDATE und DELETE auf (Keine) fest. Klicken Sie auf Fertig stellen, um den Assistenten abzuschließen.

Legen Sie die Dropdownlisten in den Registerkarten UPDATE und DELETE auf (Keine) fest.

Abbildung 10: Festlegen der Dropdownlisten in den Registerkarten UPDATE und DELETE auf (Keine) (Klicken, um das Bild in voller Größe anzuzeigen)

Nach Abschluss des Assistenten sollte das CategoriesDataSource deklarative Markup wie folgt aussehen:

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

Kehren Sie mit dem CategoriesDataSource erstellten und konfigurierten Smarttag "TemplateField" ItemTemplate zurückCategoryName, und klicken Sie im Smarttag "DropDownList" auf den Link "Datenquelle auswählen". Wählen Sie im Assistenten für die Datenquellenkonfiguration die CategoriesDataSource Option aus der ersten Dropdownliste aus, und wählen Sie aus, ob sie für die Anzeige und CategoryID als Wert verwendet werden CategoryName soll.

Binden der DropDownList an die CategoriesDataSource

Abbildung 11: Binden der DropDownList an das CategoriesDataSource Bild (Klicken, um das Bild in voller Größe anzuzeigen)

An diesem Punkt listet die Categories DropDownList alle Kategorien auf, aber sie wählt noch nicht automatisch die entsprechende Kategorie für das Produkt aus, das an die Zeile "GridView" gebunden ist. Dazu müssen wir die Categories DropDownList s SelectedValue auf den Wert des CategoryID Produkts festlegen. Klicken Sie auf den Link "DataBindings bearbeiten" aus dem Smarttag "DropDownList" und ordnen Sie die SelectedValue Eigenschaft dem CategoryID Datenfeld zu, wie in Abbildung 12 dargestellt.

Binden des Product s CategoryID-Werts an die DropDownList s SelectedValue-Eigenschaft

Abbildung 12: Binden des Product s-Werts CategoryID an die DropDownList s-Eigenschaft SelectedValue

Ein letztes Problem bleibt bestehen: Wenn das Produkt keinen angegebenen Wert aufweist CategoryID , führt die Datenbindungsanweisung zu SelectedValue einer Ausnahme. Dies liegt daran, dass die DropDownList nur Elemente für die Kategorien enthält und keine Option für diese Produkte mit einem NULL Datenbankwert bietet CategoryID. Um dies zu beheben, legen Sie die DropDownList-Eigenschaft AppendDataBoundItems auf ein True neues Element fest, und fügen Sie ein neues Element zur DropDownList hinzu, wobei die Value Eigenschaft aus der deklarativen Syntax weggelassen wird. Stellen Sie daher sicher, dass die deklarative Syntax von Categories DropDownList wie folgt aussieht:

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

Beachten Sie, dass das Attribut " <asp:ListItem Value=""> -- Select One" explizit auf eine leere Zeichenfolge festgelegt wurde Value . Im Lernprogramm zum Anpassen der Datenänderungsschnittstelle finden Sie eine ausführlichere Erläuterung dazu, warum dieses zusätzliche DropDownList-Element erforderlich ist, um den NULL Fall zu behandeln und warum die Zuweisung der Value Eigenschaft zu einer leeren Zeichenfolge unerlässlich ist.

Hinweis

Es gibt hier ein potenzielles Leistungs- und Skalierbarkeitsproblem, das erwähnt werden sollte. Da jede Zeile über eine DropDownList verfügt, die als CategoriesDataSource Datenquelle verwendet, wird die Methode der CategoriesBLL Klasse GetCategories n mal pro Seitenaufruf aufgerufen, wobei n die Anzahl der Zeilen in der GridView ist. Diese n-Aufrufe führen zu GetCategories n Abfragen an die Datenbank. Diese Auswirkungen auf die Datenbank können durch das Zwischenspeichern der zurückgegebenen Kategorien entweder in einem Anforderungscache oder über die Cacheebene mithilfe einer SQL-Zwischenspeicherungsabhängigkeit oder einem sehr kurzen zeitbasierten Ablauf verringert werden.

Schritt 4: Abschließen der Bearbeitungsschnittstelle

Wir haben eine Reihe von Änderungen an den GridView-Vorlagen vorgenommen, ohne den Fortschritt anzuzeigen. Nehmen Sie sich einen Moment Zeit, um unseren Fortschritt über einen Browser anzuzeigen. Wie in Abbildung 13 dargestellt, wird jede Zeile mithilfe ihrer ItemTemplateZelle gerendert, die die Bearbeitungsschnittstelle der Zelle enthält.

Jede GridView-Zeile kann bearbeitet werden.

Abbildung 13: Jede GridView-Zeile ist bearbeitbar (Zum Anzeigen des Bilds mit voller Größe klicken)

Es gibt einige kleinere Formatierungsprobleme, die wir an diesem Punkt berücksichtigen sollten. Beachten Sie zunächst, dass der UnitPrice Wert vier Dezimalkommapunkte enthält. Um dies zu beheben, kehren Sie zu den UnitPrice TemplateField-Objekten ItemTemplate zurück, und klicken Sie im Smarttag des TextBox-Steuerelements auf den Link "DataBindings bearbeiten". Geben Sie als Nächstes an, dass die Text Eigenschaft als Zahl formatiert werden soll.

Formatieren der Texteigenschaft als Zahl

Abbildung 14: Formatieren der Text Eigenschaft als Zahl

Zweitens, lassen Sie uns das Kontrollkästchen in der Discontinued Spalte zentrieren (anstatt es linksbündig auszurichten). Klicken Sie auf "Spalten bearbeiten" im Smarttag "GridView", und wählen Sie in der Liste der Felder in der unteren linken Ecke das Discontinued TemplateField aus. Führen Sie einen Drilldown durch ItemStyle , und legen Sie die HorizontalAlign Eigenschaft auf "Center" fest, wie in Abbildung 15 dargestellt.

Zentrzentrale des nicht mehr eingestellten CheckBox-Steuerelements

Abbildung 15: Zentrzentrale des Discontinued CheckBox-Steuerelements

Fügen Sie als Nächstes ein ValidationSummary-Steuerelement zur Seite hinzu, und legen Sie dessen ShowMessageBox Eigenschaft auf True und deren ShowSummary Eigenschaft auf False. Fügen Sie auch die Schaltflächen-Websteuerelemente hinzu, die beim Klicken die Änderungen des Benutzers aktualisieren. Fügen Sie insbesondere zwei Schaltflächen-Websteuerelemente hinzu, eine über der GridView und eine darunter, indem Sie beide Steuerelementeigenschaften Text auf "Produkte aktualisieren" festlegen.

Da die Bearbeitungsschnittstelle von GridView in den TemplateFields ItemTemplate definiert ist, sind die EditItemTemplate s überflüssig und können gelöscht werden.

Nachdem Sie die oben genannten Formatierungsänderungen vorgenommen, die Schaltflächensteuerelemente hinzugefügt und die unnötigen Elemente EditItemTemplate entfernt haben, sollte die deklarative Syntax Ihrer Seite wie folgt aussehen:

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

Abbildung 16 zeigt diese Seite, wenn sie in einem Browser angezeigt wird, nachdem die Schaltflächenwebsteuerelemente hinzugefügt wurden und die vorgenommenen Formatierungsänderungen vorgenommen wurden.

Die Seite enthält jetzt zwei Schaltflächen für Aktualisierungsprodukte.

Abbildung 16: Die Seite enthält jetzt zwei Schaltflächen "Produkte aktualisieren" (Zum Anzeigen des Bilds mit voller Größe klicken)

Schritt 5: Aktualisieren der Produkte

Wenn ein Benutzer diese Seite besucht, nimmt er seine Änderungen vor und klickt dann auf eine der beiden Schaltflächen "Produkte aktualisieren". An diesem Punkt müssen wir die vom Benutzer eingegebenen Werte für jede Zeile in eine ProductsDataTable Instanz speichern und diese dann an eine BLL-Methode übergeben, die diese ProductsDataTable Instanz dann an die DAL s-Methode UpdateWithTransaction übergibt. Die UpdateWithTransaction Methode, die wir im vorherigen Lernprogramm erstellt haben, stellt sicher, dass der Batch von Änderungen als atomer Vorgang aktualisiert wird.

Erstellen Sie eine benannte Methode BatchUpdate BatchUpdate.aspx.vb , und fügen Sie den folgenden Code hinzu:

Private Sub BatchUpdate()
    ' Enumerate the GridView's Rows collection and create a ProductRow
    Dim productsAPI As New ProductsBLL()
    Dim products As Northwind.ProductsDataTable = productsAPI.GetProducts()
    For Each gvRow As GridViewRow In ProductsGrid.Rows
        ' Find the ProductsRow instance in products that maps to gvRow
        Dim productID As Integer = _
            Convert.ToInt32(ProductsGrid.DataKeys(gvRow.RowIndex).Value)
        Dim product As Northwind.ProductsRow = products.FindByProductID(productID)
        If product IsNot Nothing Then
            ' Programmatically access the form field elements in the 
            ' current GridViewRow
            Dim productName As TextBox = _
                CType(gvRow.FindControl("ProductName"), TextBox)
            Dim categories As DropDownList = _
                CType(gvRow.FindControl("Categories"), DropDownList)
            Dim unitPrice As TextBox = _
                CType(gvRow.FindControl("UnitPrice"), TextBox)
            Dim discontinued As CheckBox = _
                CType(gvRow.FindControl("Discontinued"), CheckBox)
            ' Assign the user-entered values to the current ProductRow
            product.ProductName = productName.Text.Trim()
            If categories.SelectedIndex = 0 Then 
                product.SetCategoryIDNull() 
            Else 
                product.CategoryID = Convert.ToInt32(categories.SelectedValue)
            End If
            If unitPrice.Text.Trim().Length = 0 Then 
                product.SetUnitPriceNull() 
            Else 
                product.UnitPrice = Convert.ToDecimal(unitPrice.Text)
            End If
            product.Discontinued = discontinued.Checked
        End If
    Next
    ' Now have the BLL update the products data using a transaction
    productsAPI.UpdateWithTransaction(products)
End Sub

Diese Methode beginnt mit dem Abrufen aller Produkte in einem ProductsDataTable über einen Aufruf der BLL-Methode GetProducts . Anschließend wird die ProductGrid GridView-Auflistung Rowsaufgezählt. Die Rows Auflistung enthält eine GridViewRow Instanz für jede Zeile, die in der GridView angezeigt wird. Da wir höchstens zehn Zeilen pro Seite anzeigen, enthält die GridView-Auflistung Rows nicht mehr als zehn Elemente.

Für jede Zeile wird die Sammlung ProductID abgerufen DataKeys und die entsprechende ProductsRow aus der ProductsDataTableSammlung ausgewählt. Auf die vier TemplateField-Eingabesteuerelemente wird programmgesteuert verwiesen und deren Werte den Eigenschaften der ProductsRow Instanz zugewiesen. Nachdem die Werte jeder GridView-Zeile zum Aktualisieren der ProductsDataTableZeile verwendet wurden, wird sie an die BLL-Methode UpdateWithTransaction übergeben, die, wie wir im vorherigen Lernprogramm gesehen haben, einfach die DAL s-Methode UpdateWithTransaction aufruft.

Der für dieses Lernprogramm verwendete Batchaktualisierungsalgorithmus aktualisiert jede Zeile in der Zeile, die ProductsDataTable einer Zeile in GridView entspricht, unabhängig davon, ob die Produktinformationen geändert wurden. Während solche Blindupdates in der Regel kein Leistungsproblem sind, können sie zu überflüssigen Datensätzen führen, wenn Sie Änderungen an der Datenbanktabelle überwachen. Zurück im Lernprogramm zum Ausführen von Batchaktualisierungen haben wir eine Batchaktualisierungsschnittstelle mit der DataList untersucht und Code hinzugefügt, der nur die Datensätze aktualisiert, die tatsächlich vom Benutzer geändert wurden. Sie können die Techniken aus dem Ausführen von Batchaktualisierungen verwenden, um den Code in diesem Lernprogramm zu aktualisieren, falls gewünscht.

Hinweis

Wenn die Datenquelle über das Smarttag an das GridView gebunden wird, weist Visual Studio den Primärschlüsselwerten der Datenquelle automatisch der GridView-Eigenschaft DataKeyNames zu. Wenn Sie objectDataSource nicht über das Smarttag "GridView" an das GridView-Smarttag gebunden haben, wie in Schritt 1 beschrieben, müssen Sie die Eigenschaft "GridView" DataKeyNames manuell auf "ProductID" festlegen, um auf den ProductID Wert für jede Zeile über die DataKeys Auflistung zuzugreifen.

Der in der BLL-Methode verwendete BatchUpdate Code ähnelt dem, der in den BLL-Methoden UpdateProduct verwendet wird. Der Hauptunterschied besteht darin, dass in den UpdateProduct Methoden nur eine einzelne ProductRow Instanz aus der Architektur abgerufen wird. Der Code, der die Eigenschaften des Codes ProductRow zuweist, ist identisch zwischen den UpdateProducts Methoden und dem Code innerhalb der For Each Schleife in BatchUpdate, wie das allgemeine Muster.

Um dieses Lernprogramm abzuschließen, müssen wir die BatchUpdate Methode aufrufen lassen, wenn auf eine der Schaltflächen "Produkte aktualisieren" geklickt wird. Erstellen Sie Ereignishandler für die Click Ereignisse dieser beiden Schaltflächensteuerelemente, und fügen Sie den folgenden Code in den Ereignishandlern hinzu:

BatchUpdate()
ClientScript.RegisterStartupScript(Me.GetType(), "message", _
    "alert('The products have been updated.');", True)

Zuerst wird ein Anruf an .BatchUpdate Als Nächstes wird die ClientScript Eigenschaft verwendet, um JavaScript einzugeben, das ein Meldungsfeld anzeigt, in dem die Produkte aktualisiert wurden.

Nehmen Sie sich eine Minute Zeit, um diesen Code zu testen. Besuchen Sie BatchUpdate.aspx einen Browser, bearbeiten Sie eine Reihe von Zeilen, und klicken Sie auf eine der Schaltflächen "Produkte aktualisieren". Wenn es keine Eingabeüberprüfungsfehler gibt, sollte ein Meldungsfeld angezeigt werden, in dem die Produkte aktualisiert wurden. Um die Atomität des Updates zu überprüfen, sollten Sie eine zufällige CHECK Einschränkung hinzufügen, z. B. eine, die Werte von 1234,56 unzulässig.UnitPrice Bearbeiten Sie dann BatchUpdate.aspxeine Reihe von Datensätzen, und stellen Sie sicher, dass Sie einen der Produktwerte UnitPrice auf den unzulässigen Wert festlegen ( 1234,56 ). Dies sollte zu einem Fehler führen, wenn sie beim Klicken auf "Produkte aktualisieren" mit den anderen Änderungen während dieses Batchvorgangs auf ihre ursprünglichen Werte zurückgesetzt wurde.

Eine alternativeBatchUpdateMethode

Die BatchUpdate soeben untersuchte Methode ruft alle Produkte aus der BLL-Methode GetProducts ab und aktualisiert dann nur die Datensätze, die in GridView angezeigt werden. Dieser Ansatz ist ideal, wenn die GridView keine Paging verwendet, aber wenn dies der Fall ist, gibt es möglicherweise Hunderte, Tausende oder Zehntausende von Produkten, sondern nur zehn Zeilen in der GridView. In einem solchen Fall ist das Abrufen aller Produkte aus der Datenbank nur zum Ändern von 10 davon weniger als ideal.

Für diese Situationen sollten Sie stattdessen die folgende BatchUpdateAlternate Methode verwenden:

Private Sub BatchUpdateAlternate()
    ' Enumerate the GridView's Rows collection and create a ProductRow
    Dim productsAPI As New ProductsBLL()
    Dim products As New Northwind.ProductsDataTable()
    For Each gvRow As GridViewRow In ProductsGrid.Rows
        ' Create a new ProductRow instance
        Dim productID As Integer = _
            Convert.ToInt32(ProductsGrid.DataKeys(gvRow.RowIndex).Value)
        Dim currentProductDataTable As Northwind.ProductsDataTable = _
            productsAPI.GetProductByProductID(productID)
        If currentProductDataTable.Rows.Count > 0 Then
            Dim product As Northwind.ProductsRow = currentProductDataTable(0)
            Dim productName As TextBox = _
                CType(gvRow.FindControl("ProductName"), TextBox)
            Dim categories As DropDownList = _
                CType(gvRow.FindControl("Categories"), DropDownList)
            Dim unitPrice As TextBox = _
                CType(gvRow.FindControl("UnitPrice"), TextBox)
            Dim discontinued As CheckBox = _
                CType(gvRow.FindControl("Discontinued"), CheckBox)
            ' Assign the user-entered values to the current ProductRow
            product.ProductName = productName.Text.Trim()
            If categories.SelectedIndex = 0 Then 
                product.SetCategoryIDNull() 
            Else 
                product.CategoryID = Convert.ToInt32(categories.SelectedValue)
            End If
            If unitPrice.Text.Trim().Length = 0 Then 
                product.SetUnitPriceNull() 
            Else 
                product.UnitPrice = Convert.ToDecimal(unitPrice.Text)
            End If
            product.Discontinued = discontinued.Checked
            ' Import the ProductRow into the products DataTable
            products.ImportRow(product)
        End If
    Next
    ' Now have the BLL update the products data using a transaction
    productsAPI.UpdateProductsWithTransaction(products)
End Sub

BatchMethodAlternate beginnt mit dem Erstellen eines neuen leeren ProductsDataTable Namens products. Anschließend wird die GridView-Sammlung Rows durchlaufen, und für jede Zeile werden die spezifischen Produktinformationen mithilfe der BLL-Methode GetProductByProductID(productID) angezeigt. Die abgerufene ProductsRow Instanz hat ihre Eigenschaften auf die gleiche Weise aktualisiert wie BatchUpdate, aber nach dem Aktualisieren der Zeile wird sie über die DataTable-MethodeImportRow(DataRow) in die products ProductsDataTable Datentabelle importiert.

Nach Abschluss products der For Each Schleife enthält sie eine ProductsRow Instanz für jede Zeile in gridView. Da jede instanz ProductsRow der (statt aktualisiert) hinzugefügt wurde products , wird sie blind an die UpdateWithTransaction Methode übergeben, die versucht, ProductsTableAdapter die einzelnen Datensätze in die Datenbank einzufügen. Stattdessen müssen wir angeben, dass jede dieser Zeilen geändert wurde (nicht hinzugefügt).

Dies kann durch Hinzufügen einer neuen Methode zur BLL mit dem Namen UpdateProductsWithTransactionerreicht werden. UpdateProductsWithTransaction, siehe unten, legt die RowState einzelnen ProductsRow Instanzen in der ProductsDataTable an Modified und übergibt dann die ProductsDataTable DAL s-Methode UpdateWithTransaction .

Public Function UpdateProductsWithTransaction _
    (ByVal products As Northwind.ProductsDataTable) As Integer
    ' Mark each product as Modified
    products.AcceptChanges()
    For Each product As Northwind.ProductsRow In products
        product.SetModified()
    Next
    ' Update the data via a transaction
    Return UpdateWithTransaction(products)
End Function

Zusammenfassung

GridView bietet integrierte Bearbeitungsfunktionen pro Zeile, bietet jedoch keine Unterstützung für das Erstellen vollständig bearbeitbarer Schnittstellen. Wie wir in diesem Lernprogramm gesehen haben, sind solche Schnittstellen möglich, erfordern aber etwas Arbeit. Um eine GridView zu erstellen, in der jede Zeile bearbeitbar ist, müssen wir die GridView-Felder in TemplateFields konvertieren und die Bearbeitungsschnittstelle innerhalb der ItemTemplate Objekte definieren. Darüber hinaus müssen Websteuerelemente vom Typ "Alle Schaltflächen aktualisieren" der Seite hinzugefügt werden, getrennt von gridView. Diese Schaltflächen-Ereignishandler Click müssen die GridView-Auflistung Rows aufzählen, die Änderungen in einem ProductsDataTableSpeicher speichern und die aktualisierten Informationen an die entsprechende BLL-Methode übergeben.

Im nächsten Lernprogramm erfahren Sie, wie Sie eine Schnittstelle zum Löschen von Batchs erstellen. Insbesondere enthält jede GridView-Zeile ein Kontrollkästchen, und anstelle von Schaltflächen vom Typ "Alle aktualisieren" verfügen wir über Schaltflächen "Ausgewählte Zeilen löschen".

Glückliche Programmierung!

Zum Autor

Scott Mitchell, Autor von sieben ASP/ASP.NET Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft Web Technologies zusammen. Scott arbeitet als unabhängiger Berater, Trainer und Schriftsteller. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 2.0 in 24 Stunden. Er kann über mitchell@4GuysFromRolla.com seinen Blog erreicht werden, der unter .http://ScottOnWriting.NET

Besonderer Dank an

Diese Lernprogrammreihe wurde von vielen hilfreichen Prüfern überprüft. Leitende Prüfer für dieses Lernprogramm waren Teresa Murphy und David Suru. Möchten Sie meine bevorstehenden MSDN-Artikel überprüfen? Wenn dies der Fall ist, legen Sie mir eine Zeile bei mitchell@4GuysFromRolla.com.