Aktualisieren in Batches (VB)
von Scott Mitchell
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.
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 ProductsDataSource
zu binden. Konfigurieren Sie objectDataSource so, dass sie die Daten aus der Methode der ProductsBLL
Klasse abruft GetProducts
.
Abbildung 2: Konfigurieren der ObjectDataSource für die Verwendung der Klasse (Zum Anzeigen des ProductsBLL
Bilds mit voller Größe klicken)
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.
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 ProductName
Felder , CategoryName
UnitPrice
und 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
, CategoryName
und UnitPrice
) und ein CheckBoxField (Discontinued
). Wir müssen diese vier Felder in TemplateFields konvertieren und dann die Bearbeitungsschnittstelle aus den TemplateFields EditItemTemplate
in das ItemTemplate
Feld 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.
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 derProductName
UnitPrice
Schnittstellen undDiscontinued
Bearbeiten von Schnittstellen
Das Erstellen der ProductName
Schnittstellen und Discontinued
UnitPrice
Bearbeitungsschnittstellen ist das Thema dieses Schritts und ist ziemlich unkompliziert, da jede Schnittstelle bereits in den TemplateField-Elementen EditItemTemplate
definiert 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 EditItemTemplate
durch. Wählen Sie das TextBox-Objekt aus, kopieren Sie es in die Zwischenablage, und fügen Sie es dann in das ProductName
TemplateField s ItemTemplate
ein. Ä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 ItemTemplate
Bildschirm vorgenommen haben, sollte Ihr Bildschirm ähnlich aussehen wie in Abbildung 6.
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 .
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 ItemTemplate
Datei definierte CheckBox-Steuerelement verwenden. Legen Sie den ID
Wert einfach auf "Nicht eingestellt" und seine Enabled
Eigenschaft auf True
" fest.
Schritt 3: Erstellen derCategoryName
Bearbeitungsschnittstelle
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 ItemTemplate
Objekts 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
.
Abbildung 8: Konfigurieren der ObjectDataSource für die Verwendung der CategoriesBLL
Klasse (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
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.
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.
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.
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 ItemTemplate
Zelle gerendert, die die Bearbeitungsschnittstelle der Zelle enthält.
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.
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.
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.
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 Rows
aufgezä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 ProductsDataTable
Sammlung 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 ProductsDataTable
Zeile 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.aspx
eine 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 alternativeBatchUpdate
Methode
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 UpdateProductsWithTransaction
erreicht 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 ProductsDataTable
Speicher 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.