Aktualisieren in Batches (C#)
von Scott Mitchell
Erfahren Sie, wie Sie mehrere Datenbankdatensätze in einem einzelnen Vorgang aktualisieren. In der Benutzeroberflächenebene erstellen wir ein GridView-Objekt, in dem jede Zeile bearbeitet werden kann. Auf der Datenzugriffsebene werden die verschiedenen Updatevorgänge innerhalb einer Transaktion umgebrochen, um sicherzustellen, dass alle Updates erfolgreich sind oder dass ein Rollback für alle Updates ausgeführt wird.
Einführung
Im vorherigen Tutorial haben wir erfahren, wie Sie die Datenzugriffsebene erweitern, um Unterstützung für Datenbanktransaktionen hinzuzufügen. Datenbanktransaktionen garantieren, dass eine Reihe von Datenänderungsanweisungen als ein atomischer 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 richten.
In diesem Tutorial erstellen wir ein GridView-Objekt, in dem jede Zeile bearbeitet werden kann (siehe Abbildung 1). Da jede Zeile in ihrer Bearbeitungsoberfläche gerendert wird, ist keine Spalte der Schaltflächen Bearbeiten, Aktualisieren und Abbrechen erforderlich. Stattdessen gibt es zwei Schaltflächen Produkte aktualisieren auf der Seite, die bei Klick die GridView-Zeilen aufzählen und die Datenbank aktualisieren.
Abbildung 1: Jede Zeile in GridView ist bearbeitbar (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Lassen Sie uns loslegen!
Hinweis
Im Tutorial Ausführen von Batch Updates haben wir eine Batchbearbeitungsschnittstelle mithilfe des DataList-Steuerelements erstellt. Dieses Tutorial unterscheidet sich vom vorherigen Tutorial darin, dass eine GridView verwendet wird und die Batchaktualisierung innerhalb des Bereichs einer Transaktion ausgeführt wird. Nach Abschluss dieses Tutorials ermuntern Sie, zum vorherigen Tutorial zurückzukehren und es so zu aktualisieren, dass die datenbanktransaktionsbezogene Funktionalität verwendet wird, die im vorherigen Tutorial hinzugefügt wurde.
Untersuchen der Schritte zum Bearbeiten aller GridView-Zeilen
Wie im Tutorial Eine Übersicht über das Einfügen, Aktualisieren und Löschen von Daten erläutert, bietet GridView integrierte Unterstützung für die Zeilenbearbeitung der zugrunde liegenden Daten. Intern notiert gridView, welche Zeile über die EditIndex
-Eigenschaft bearbeitet werden kann. Da gridView an seine Datenquelle gebunden wird, überprüft es jede Zeile, um festzustellen, ob der Index der Zeile dem Wert von EditIndex
entspricht. Wenn ja, werden diese Zeilenfelder mithilfe ihrer Bearbeitungsschnittstellen gerendert. Für BoundFields ist die Bearbeitungsschnittstelle ein TextBox-Objekt, dessen Text
Eigenschaft dem Wert des Datenfelds zugewiesen wird, das von der BoundField s-Eigenschaft DataField
angegeben wird. Für TemplateFields wird anstelle EditItemTemplate
von ItemTemplate
verwendet.
Denken Sie daran, dass der Bearbeitungsworkflow gestartet wird, wenn ein Benutzer auf die Schaltfläche Bearbeiten einer Zeile klickt. Dies führt zu einem Postback, legt die GridView-Eigenschaft auf EditIndex
den Index des geklickten Zeilens fest und binden die Daten erneut an das Raster. Wenn auf die Schaltfläche Abbrechen einer Zeile geklickt wird, wird beim Postback auf EditIndex
den Wert von -1
festgelegt, bevor die Daten erneut an das Raster binden. Da die Zeilen von GridView die Indizierung bei Null beginnen, hat die Einstellung EditIndex
auf -1
die Auswirkung, dass gridView im schreibgeschützten Modus angezeigt wird.
Die EditIndex
-Eigenschaft eignet sich gut für die Zeilenbearbeitung, ist aber nicht für die Batchbearbeitung konzipiert. Damit das gesamte GridView bearbeitbar ist, muss jede Zeile mithilfe der Bearbeitungsoberfläche gerendert werden. Die einfachste Möglichkeit, dies zu erreichen, besteht darin, zu erstellen, wo jedes bearbeitbare Feld als TemplateField implementiert wird, dessen Bearbeitungsschnittstelle im ItemTemplate
definiert ist.
In den nächsten Schritten erstellen wir eine vollständig bearbeitbare GridView. In Schritt 1 beginnen wir mit dem Erstellen von GridView und seiner ObjectDataSource und konvertieren die zugehörigen BoundFields und CheckBoxField in TemplateFields. In Den Schritten 2 und 3 verschieben wir die Bearbeitungsschnittstellen von den TemplateFields EditItemTemplate
in die ItemTemplate
entsprechenden.
Schritt 1: Anzeigen von Produktinformationen
Bevor wir uns gedanken über das Erstellen einer GridView machen, bei der Zeilen bearbeitbar sind, beginnen wir mit der Anzeige der Produktinformationen. Öffnen Sie die BatchUpdate.aspx
Seite im BatchData
Ordner, und ziehen Sie ein GridView-Objekt aus der Toolbox auf die Designer. Legen Sie die GridViews ID
auf ProductsGrid
fest, und wählen Sie aus ihrem Smarttag aus, um sie an eine neue ObjectDataSource namens ProductsDataSource
zu binden. Konfigurieren Sie die ObjectDataSource, um ihre Daten aus der s-Methode GetProducts
der ProductsBLL
Klasse abzurufen.
Abbildung 2: Konfigurieren der ObjectDataSource für die Verwendung der ProductsBLL
-Klasse (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Abbildung 3: Abrufen der Produktdaten mithilfe der GetProducts
-Methode (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Wie gridView sind die Änderungsfeatures von ObjectDataSource so konzipiert, dass sie zeilenweise funktionieren. Um eine Reihe von Datensätzen zu aktualisieren, müssen wir ein wenig Code in die CodeBehind-Klasse der ASP.NET Seite schreiben, die die Daten in Batches übergibt und sie an die BLL übergibt. Legen Sie daher die Dropdownlisten in den Registerkarten UPDATE, INSERT und DELETE von ObjectDataSource auf (Keine) fest. Klicken Sie auf Fertig stellen, um den Assistenten abzuschließen.
Abbildung 4: Festlegen der Drop-Down Listen in den Registerkarten UPDATE, INSERT und DELETE auf (Keine) (Klicken Sie hier, 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 von Datenquellen ausführen, erstellt Visual Studio auch BoundFields und ein CheckBoxField für die Produktdatenfelder in GridView. In diesem Tutorial können Benutzer nur den Namen, die Kategorie, den Preis und die eingestellten status anzeigen und bearbeiten. Entfernen Sie alle Felder außer ProductName
, CategoryName
, UnitPrice
und Discontinued
, und benennen Sie die HeaderText
Eigenschaften der ersten drei Felder in Product, Category und Price um. Aktivieren Sie schließlich die Kontrollkästchen Paging aktivieren und Sortierung aktivieren im Smarttag von 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 Bearbeitungsoberfläche von den TemplateFields EditItemTemplate
in die zugehörige ItemTemplate
verschieben.
Hinweis
Das Erstellen und Anpassen von TemplateFields wurde im Tutorial Anpassen der Datenänderungsschnittstelle untersucht. Wir werden die Schritte zum Konvertieren von BoundFields und CheckBoxField in TemplateFields und zum Definieren der Bearbeitungsschnittstellen in ihren ItemTemplate
s durchlaufen. Wenn Sie jedoch hängen bleiben oder eine Auffrischung benötigen, zögern Sie nicht, auf dieses frühere Tutorial zurück zu verweisen.
Klicken Sie im Smarttag von 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 den Link Dieses Feld in ein TemplateField konvertieren.
Abbildung 5: Konvertieren der vorhandenen BoundFields und CheckBoxField in TemplateField
Nachdem jedes Feld ein TemplateField ist, können wir die Bearbeitungsoberfläche nun von den EditItemTemplate
s in die ItemTemplate
s verschieben.
Schritt 2: Erstellen derProductName
UnitPrice
Schnittstellen, undDiscontinued
Bearbeitungsschnittstellen
Das Erstellen der ProductName
Schnittstellen , UnitPrice
, und Discontinued
ist das Thema dieses Schritts und ziemlich einfach, da jede Schnittstelle bereits in TemplateField definiert EditItemTemplate
ist. Das Erstellen der CategoryName
Bearbeitungsoberfläche ist etwas komplizierter, da wir eine DropDownList der entsprechenden Kategorien erstellen müssen. Diese CategoryName
Bearbeitungsschnittstelle 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 zu TemplateField ProductName
s aus EditItemTemplate
. Wählen Sie das Textfeld aus, kopieren Sie es in die Zwischenablage, und fügen Sie es dann in templateField ProductName
ein ItemTemplate
. Ändern Sie die TextBox-Eigenschaft in ID
ProductName
.
Fügen Sie als Nächstes einen RequiredFieldValidator zu hinzu ItemTemplate
, um sicherzustellen, dass der Benutzer einen Wert für jeden Produktnamen bereitstellt. Legen Sie die ControlToValidate
-Eigenschaft auf ProductName und die ErrorMessage
-Eigenschaft auf Sie müssen den Namen des Produkts angeben fest. und die Text
-Eigenschaft auf *. Nachdem Sie diese Ergänzungen am ItemTemplate
gemacht haben, sollte Ihr Bildschirm ähnlich wie Abbildung 6 aussehen.
Abbildung 6: Das ProductName
TemplateField enthält jetzt ein TextBox und ein RequiredFieldValidator (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Beginnen Sie für die UnitPrice
Bearbeitungsoberfläche, indem Sie das TextBox-Element von in EditItemTemplate
kopieren ItemTemplate
. Platzieren Sie als Nächstes ein $ vor dem TextBox-Element, und legen Sie seine 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 größer oder gleich $0,00 ist. Legen Sie die Validierungseigenschaft auf ControlToValidate
UnitPrice und ihre ErrorMessage
Eigenschaft auf Sie müssen einen gültigen Währungswert eingeben fest. Lassen Sie alle Währungssymbole aus., die Text
-Eigenschaft auf *, die Type
-Eigenschaft auf Currency
, die Operator
-Eigenschaft auf GreaterThanEqual
, und die 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 in voller Größe anzuzeigen)
Für das Discontinued
TemplateField können Sie das bereits im definierten ItemTemplate
CheckBox verwenden. Legen Sie einfach auf ID
Discontinued und die Enabled
-Eigenschaft auf fest true
.
Schritt 3: Erstellen der BearbeitungsschnittstelleCategoryName
Die Bearbeitungsoberfläche in den CategoryName
TemplateFields 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 Tutorial Anpassen der Datenänderungsschnittstelle enthält eine ausführlichere und umfassendere Erläuterung zum Anpassen einer Vorlage, um eine DropDownList anstelle eines TextBox-Elements einzuschließen. Während die hier beschriebenen Schritte abgeschlossen sind, werden sie nur sehr kurz dargestellt. Einen ausführlicheren Einblick in das Erstellen und Konfigurieren der Kategorien DropDownList finden Sie im Tutorial Anpassen der Datenänderungsschnittstelle .
Ziehen Sie eine DropDownList aus der Toolbox auf das CategoryName
TemplateField-Element, ItemTemplate
und legen Sie dessen ID
auf fest Categories
. An diesem Punkt definieren wir in der Regel die DropDownLists-Datenquelle über das zugehörige Smarttag, wodurch eine neue ObjectDataSource erstellt wird. Dadurch wird jedoch die ObjectDataSource innerhalb von ItemTemplate
hinzugefügt, was zu einer ObjectDataSource-instance führt, die für jede GridView-Zeile erstellt wird. Stattdessen erstellen wir die ObjectDataSource außerhalb von GridView s TemplateFields. Beenden Sie die Vorlagenbearbeitung, und ziehen Sie eine ObjectDataSource aus der Toolbox auf die Designer unter objectDataSourceProductsDataSource
. Benennen Sie die neue ObjectDataSourceCategoriesDataSource
, und konfigurieren Sie sie für die Verwendung der s-Methode GetCategories
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)
Abbildung 9: Abrufen der Kategoriedaten mithilfe der GetCategories
-Methode (Klicken Sie hier, 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 Drop-Down Listen in den Registerkarten UPDATE und DELETE auf (Keine) (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Nach Abschluss des Assistenten sollte das CategoriesDataSource
deklarative Markup von s wie folgt aussehen:
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
Kehren Sie nach dem CategoriesDataSource
Erstellten und Konfigurierten zu den CategoryName
TemplateFields ItemTemplate
zurück, und klicken Sie im Smarttag DropDownList auf den Link Datenquelle auswählen. Wählen Sie im Datenquellenkonfigurations-Assistenten die CategoriesDataSource
Option aus der ersten Dropdownliste aus, und wählen Sie CategoryName
für die Anzeige und CategoryID
als Wert aus.
Abbildung 11: Binden der DropDownList an die CategoriesDataSource
(Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
An diesem Punkt listet dropDownList Categories
alle Kategorien auf, wählt aber noch nicht automatisch die entsprechende Kategorie für das Produkt aus, das an die GridView-Zeile gebunden ist. Um dies zu erreichen, müssen wir die Categories
DropDownList s SelectedValue
auf den Wert des CategoryID
Produkts festlegen. Klicken Sie im Smarttag DropDownList auf den Link DataBindings bearbeiten, 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-Eigenschaft SelectedValue
Ein letztes Problem bleibt bestehen: Wenn für das Produkt kein CategoryID
Wert angegeben ist, führt die Datenbindungsanweisung zu SelectedValue
einer Ausnahme. Dies liegt daran, dass DropDownList nur Elemente für die Kategorien enthält und keine Option für die Produkte bietet, die über einen NULL
Datenbankwert für CategoryID
verfügen. Um dies zu beheben, legen Sie die DropDownList-Eigenschaft AppendDataBoundItems
auf fest true
, und fügen Sie der DropDownList ein neues Element hinzu, wobei die Value
Eigenschaft aus der deklarativen Syntax weggelassen wird. Stellen Sie also 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 <asp:ListItem Value="">
-- Select One-Attribut explizit auf eine leere Zeichenfolge festgelegt ist Value
. Im Tutorial Anpassen der Datenänderungsschnittstelle finden Sie eine ausführlichere Erläuterung, 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ähnenswert ist. Da jede Zeile über eine DropDownList verfügt, die den CategoriesDataSource
als Datenquelle verwendet, wird die Methode der CategoriesBLL
Klasse s GetCategories
n mal pro Seitenbesuch aufgerufen, wobei n die Anzahl der Zeilen in GridView ist. Diese n-Aufrufe führen zu GetCategories
n-Abfragen an die Datenbank. Diese Auswirkungen auf die Datenbank können verringert werden, indem die zurückgegebenen Kategorien entweder in einem Anforderungscache oder über die Cacheebene mithilfe einer SQL-Zwischenspeicherungsabhängigkeit oder eines sehr kurzen zeitbasierten Ablaufs zwischengespeichert werden.
Schritt 4: Abschließen der Bearbeitungsschnittstelle
Wir haben eine Reihe von Änderungen an den GridView-Vorlagen vorgenommen, ohne anzuhalten, um unseren Fortschritt anzuzeigen. Nehmen Sie sich einen Moment Zeit, um unseren Fortschritt über einen Browser anzuzeigen. Wie in Abbildung 13 dargestellt, wird jede Zeile mithilfe von ItemTemplate
gerendert, die die Bearbeitungsschnittstelle der Zelle enthält.
Abbildung 13: Jede GridView-Zeile ist bearbeitbar (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Es gibt einige kleinere Formatierungsprobleme, die wir an dieser Stelle berücksichtigen sollten. Beachten Sie zunächst, dass der UnitPrice
Wert vier Dezimalstellen enthält. Um dies zu beheben, kehren Sie zu TemplateField UnitPrice
s ItemTemplate
zurück, und klicken Sie im Smarttag TextBox 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 das Kontrollkästchen in der Discontinued
Spalte zentrieren (anstatt es links ausgerichtet zu haben). Klicken Sie im Smarttag von GridView auf Spalten bearbeiten, und wählen Sie in der Discontinued
Liste der Felder in der unteren linken Ecke das TemplateField aus. Führen Sie einen Drilldown durch ItemStyle
, und legen Sie die HorizontalAlign
Eigenschaft wie in Abbildung 15 dargestellt auf Zentriert fest.
Abbildung 15: Zentrierendes Discontinued
CheckBox
Fügen Sie als Nächstes der Seite ein ValidationSummary-Steuerelement hinzu, und legen Sie die ShowMessageBox
-Eigenschaft auf true
und die ShowSummary
-Eigenschaft auf fest false
. Fügen Sie auch die Schaltflächenwebsteuerelemente hinzu, die beim Klicken die Änderungen des Benutzers aktualisieren. Fügen Sie insbesondere zwei Button-Websteuerelemente hinzu, eines über der GridView und eines darunter, und legen Sie beide Steuerelementeigenschaften Text
auf Produkte aktualisieren fest.
Da die Bearbeitungsschnittstelle von GridView in ihren 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ächen-Steuerelemente hinzugefügt und die unnötigen EditItemTemplate
s 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 über einen Browser angezeigt wird, nachdem die Schaltflächen-Websteuerelemente hinzugefügt und die Formatierungsänderungen vorgenommen wurden.
Abbildung 16: Die Seite enthält jetzt zwei Schaltflächen "Produkte aktualisieren" (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
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 irgendwie in einem ProductsDataTable
instance speichern und diese dann an eine BLL-Methode übergeben, die dann diese ProductsDataTable
instance an die DAL s-Methode UpdateWithTransaction
übergibt. Die UpdateWithTransaction
-Methode, die wir im vorherigen Tutorial erstellt haben, stellt sicher, dass der Änderungsbatch als atomischer Vorgang aktualisiert wird.
Erstellen Sie eine Methode namens BatchUpdate
in BatchUpdate.aspx.cs
, und fügen Sie den folgenden Code hinzu:
private void BatchUpdate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = productsAPI.GetProducts();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Find the ProductsRow instance in products that maps to gvRow
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsRow product = products.FindByProductID(productID);
if (product != null)
{
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateWithTransaction(products);
}
Diese Methode beginnt mit dem Abrufen aller Produkte in einem ProductsDataTable
über einen Aufruf der BLL s-Methode GetProducts
. Anschließend wird die ProductGrid
GridView-Auflistung Rows
aufgelistet. Die Rows
Auflistung enthält eine GridViewRow
instance für jede Zeile, die in GridView angezeigt wird. Da maximal zehn Zeilen pro Seite angezeigt werden, enthält die GridView-Auflistung Rows
nicht mehr als zehn Elemente.
Für jede Zeile wird aus ProductID
der DataKeys
Auflistung gegriffen, und die entsprechende ProductsRow
wird aus dem ProductsDataTable
ausgewählt. Auf die vier TemplateField-Eingabesteuerelemente wird programmgesteuert verwiesen, und ihre Werte werden den Eigenschaften des ProductsRow
instance zugewiesen. Nachdem jeder GridView-Zeilenwert verwendet wurde, um den ProductsDataTable
zu aktualisieren, wird er an die BLL-Methode UpdateWithTransaction
übergeben, die, wie im vorherigen Tutorial gezeigt, einfach in die DAL s-Methode UpdateWithTransaction
herunterruft.
Der für dieses Tutorial verwendete Batchupdatealgorithmus aktualisiert jede Zeile in der , die ProductsDataTable
einer Zeile in GridView entspricht, unabhängig davon, ob die Produktinformationen geändert wurden. Obwohl solche blinden Updates 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 Tutorial Ausführen von Batch Updates haben wir eine Batchaktualisierungsschnittstelle mit 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 von Performing Batch Updates verwenden, um den Code in diesem Tutorial bei Bedarf zu aktualisieren.
Hinweis
Wenn die Datenquelle über das Smarttag an gridView gebunden wird, weist Visual Studio automatisch die Primärschlüsselwerte der Datenquelle der GridView-Eigenschaft DataKeyNames
zu. Wenn Sie die ObjectDataSource nicht wie in Schritt 1 beschrieben über das Smarttag von GridView an gridView gebunden haben, müssen Sie die GridView-Eigenschaft DataKeyNames
manuell auf ProductID festlegen, um über die DataKeys
Auflistung auf den ProductID
Wert für jede Zeile zuzugreifen.
Der in BatchUpdate
verwendete Code ähnelt dem in den BLL-MethodenUpdateProduct
. Der Standard Unterschied besteht darin, dass in den UpdateProduct
Methoden nur ein einzelner ProductRow
instance aus der Architektur abgerufen wird. Der Code, der die Eigenschaften von ProductRow
zuweist, ist zwischen den UpdateProducts
Methoden und dem Code innerhalb der foreach
Schleife in BatchUpdate
identisch, ebenso wie das Gesamtmuster.
Um dieses Tutorial abzuschließen, muss die BatchUpdate
-Methode aufgerufen werden, wenn auf eine der Schaltflächen Produkte aktualisieren geklickt wird. Erstellen Sie Ereignishandler für die Click
Ereignisse dieser beiden Button-Steuerelemente, und fügen Sie den Ereignishandlern den folgenden Code hinzu:
BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message",
"alert('The products have been updated.');", true);
Zuerst wird ein Aufruf von BatchUpdate
ausgeführt. Als Nächstes wird verwendet, um JavaScript einzugeben, in dem ein Meldungsfeld mit dem ClientScript property
Text Die Produkte wurden aktualisiert angezeigt wird.
Nehmen Sie sich eine Minute Zeit, um diesen Code zu testen. Rufen Sie BatchUpdate.aspx
einen Browser auf, bearbeiten Sie eine Reihe von Zeilen, und klicken Sie auf eine der Schaltflächen Produkte aktualisieren. Wenn keine Eingabevalidierungsfehler vorliegen, sollte ein Meldungsfeld mit dem Text Die Produkte wurden aktualisiert angezeigt. Um die Atomarität des Updates zu überprüfen, sollten Sie eine zufällige CHECK
Einschränkung hinzufügen, z. B. eine Einschränkung, die werte von 1234,56 nicht zuzulassen UnitPrice
. Bearbeiten Sie dann aus BatchUpdate.aspx
eine Reihe von Datensätzen, und stellen Sie sicher, dass Sie einen wert des Produkts UnitPrice
auf den unzulässigen Wert ( 1234,56 ) festlegen. Dies sollte zu einem Fehler führen, wenn beim Klicken auf Produkte aktualisieren mit den anderen Änderungen während dieses Batchvorgangs ein Rollback auf die ursprünglichen Werte erfolgt ist.
Eine alternativeBatchUpdate
Methode
Die BatchUpdate
soeben untersuchte Methode ruft alle Produkte aus der BLL-Methode ab GetProducts
und aktualisiert dann nur die Datensätze, die in GridView angezeigt werden. Dieser Ansatz ist ideal, wenn gridView kein Paging verwendet, aber wenn dies der Fall ist, kann es Hunderte, Tausende oder Zehntausende von Produkten geben, aber nur zehn Zeilen in GridView. In einem solchen Fall ist es weniger als ideal, alle Produkte aus der Datenbank zu erhalten, um 10 davon zu ändern.
Für diese Arten von Situationen sollten Sie stattdessen die folgende BatchUpdateAlternate
Methode verwenden:
private void BatchUpdateAlternate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Create a new ProductRow instance
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsDataTable currentProductDataTable =
productsAPI.GetProductByProductID(productID);
if (currentProductDataTable.Rows.Count > 0)
{
Northwind.ProductsRow product = currentProductDataTable[0];
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
// Import the ProductRow into the products DataTable
products.ImportRow(product);
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateProductsWithTransaction(products);
}
BatchMethodAlternate
beginnt, indem ein neues leeres ProductsDataTable
namens erstellt wird products
. Anschließend wird die GridView-Sammlung Rows
durchlaufen und für jede Zeile die jeweiligen Produktinformationen mithilfe der BLL-Methode s GetProductByProductID(productID)
abgerufen. Für die abgerufene ProductsRow
instance werden die Eigenschaften auf die gleiche Weise wie BatchUpdate
aktualisiert, aber nach dem Aktualisieren der Zeile wird sie über die DataTable-Methode in ImportRow(DataRow)
importiertproducts``ProductsDataTable
.
Enthält nach Abschluss products
der foreach
Schleife eine ProductsRow
instance für jede Zeile in GridView. Da jede der ProductsRow
Instanzen der products
hinzugefügt wurde (statt aktualisiert), wenn wir sie blind an die UpdateWithTransaction
-Methode übergeben, versucht der ProductsTableAdapter
, jeden der Datensätze in die Datenbank einzufügen. Stattdessen müssen wir angeben, dass jede dieser Zeilen geändert (nicht hinzugefügt) wurde.
Dies kann erreicht werden, indem Sie der BLL eine neue Methode mit dem Namen UpdateProductsWithTransaction
hinzufügen. UpdateProductsWithTransaction
, wie unten dargestellt, legt die der einzelnen ProductsRow
Instanzen im ProductsDataTable
an fest Modified
und übergibt dann die ProductsDataTable
an die DAL s-MethodeUpdateWithTransaction
.RowState
public int UpdateProductsWithTransaction(Northwind.ProductsDataTable products)
{
// Mark each product as Modified
products.AcceptChanges();
foreach (Northwind.ProductsRow product in products)
product.SetModified();
// Update the data via a transaction
return UpdateWithTransaction(products);
}
Zusammenfassung
GridView bietet integrierte Funktionen für die Zeilenbearbeitung, unterstützt jedoch nicht das Erstellen vollständig bearbeitbarer Schnittstellen. Wie wir in diesem Tutorial gesehen haben, sind solche Schnittstellen möglich, erfordern aber etwas Arbeit. Um ein GridView-Objekt zu erstellen, in dem jede Zeile bearbeitbar ist, müssen wir die GridView-Felder in TemplateFields konvertieren und die Bearbeitungsoberfläche innerhalb der ItemTemplate
s definieren. Darüber hinaus müssen alle Schaltflächen-Websteuerelemente vom Typ "Alle aktualisieren" getrennt von GridView zur Seite hinzugefügt werden. Diese Buttons-Ereignishandler Click
müssen die GridView-Auflistung Rows
aufzählen, die Änderungen in einem ProductsDataTable
speichern und die aktualisierten Informationen an die entsprechende BLL-Methode übergeben.
Im nächsten Tutorial erfahren Sie, wie Sie eine Schnittstelle zum Löschen von Batchs erstellen. Insbesondere enthält jede GridView-Zeile ein Kontrollkästchen, und anstelle der Schaltflächen Alle aktualisieren haben wir die Schaltflächen Ausgewählte Zeilen löschen.
Viel Spaß beim Programmieren!
Zum Autor
Scott Mitchell, Autor von sieben ASP/ASP.NET-Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft-Webtechnologien. Scott arbeitet als unabhängiger Berater, Trainer und Autor. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Er kann unter mitchell@4GuysFromRolla.comoder über seinen Blog erreicht werden, der unter http://ScottOnWriting.NETzu finden ist.
Besonderer Dank an
Diese Tutorialreihe wurde von vielen hilfreichen Prüfern überprüft. Hauptprüfer für dieses Tutorial waren Teresa Murphy und David Suru. Möchten Sie meine bevorstehenden MSDN-Artikel lesen? Wenn dies der Fall ist, legen Sie eine Zeile unter abmitchell@4GuysFromRolla.com.