Einfügen in Batches (VB)
von Scott Mitchell
Erfahren Sie, wie Sie mehrere Datenbankdatensätze in einem einzelnen Vorgang einfügen. In der Benutzeroberflächenebene erweitern wir gridView, damit der Benutzer mehrere neue Datensätze eingeben kann. In der Datenzugriffsebene werden die mehreren Einfügevorgänge innerhalb einer Transaktion umgebrochen, um sicherzustellen, dass alle Einfügungen erfolgreich sind oder dass ein Rollback für alle Einfügungen ausgeführt wird.
Einführung
Im Tutorial zum Batchupdate haben wir uns mit dem Anpassen des GridView-Steuerelements befasst, um eine Schnittstelle darzustellen, in der mehrere Datensätze bearbeitet werden können. Der Benutzer, der die Seite besucht, kann eine Reihe von Änderungen vornehmen und dann mit einem einzigen Klick auf eine Schaltfläche eine Batchaktualisierung durchführen. In Situationen, in denen Benutzer häufig viele Datensätze auf einmal aktualisieren, kann eine solche Benutzeroberfläche im Vergleich zu den standardmäßigen Zeilenbearbeitungsfeatures, die zuerst im Tutorial Übersicht über Einfügen, Aktualisieren und Löschen von Daten untersucht wurden, unzählige Klicks und Kontextwechsel zwischen Tastatur und Maus speichern.
Dieses Konzept kann auch beim Hinzufügen von Datensätzen angewendet werden. Stellen Sie sich vor, dass wir hier bei Northwind Traders häufig Sendungen von Lieferanten erhalten, die eine Reihe von Produkten für eine bestimmte Kategorie enthalten. Als Beispiel könnten wir eine Lieferung von sechs verschiedenen Tee- und Kaffeeprodukten von Tokyo Traders erhalten. Wenn ein Benutzer die sechs Produkte einzeln über ein DetailsView-Steuerelement eingibt, muss er viele der gleichen Werte immer wieder auswählen: Er muss dieselbe Kategorie (Getränke), denselben Lieferanten (Tokyo Traders), denselben nicht mehr eingestellten Wert (False) und die gleichen Einheiten für den Bestellwert (0) auswählen. Diese sich wiederholende Dateneingabe ist nicht nur zeitaufwändig, sondern auch fehleranfällig.
Mit etwas Arbeit können wir eine Batcheinfügungsschnittstelle erstellen, die es dem Benutzer ermöglicht, den Lieferanten und die Kategorie einmal auszuwählen, eine Reihe von Produktnamen und Stückpreisen einzugeben und dann auf eine Schaltfläche zu klicken, um die neuen Produkte zur Datenbank hinzuzufügen (siehe Abbildung 1). Wenn jedes Produkt hinzugefügt wird, werden seinen ProductName
Datenfeldern und UnitPrice
die in den TextBoxen eingegebenen Werte zugewiesen, während dessen CategoryID
- und SupplierID
-Werte die Werte aus den DropDownLists am oberen Rand des Formulars zugewiesen werden. Die Discontinued
Werte und UnitsOnOrder
werden auf die hartcodierten Werte von False
und 0 festgelegt.
Abbildung 1: Die Batcheinfügungsschnittstelle (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
In diesem Tutorial erstellen wir eine Seite, die die in Abbildung 1 gezeigte Schnittstelle zum Einfügen von Batchs implementiert. Wie in den vorherigen beiden Tutorials werden die Einfügungen in den Bereich einer Transaktion eingeschlossen, um die Atomarität sicherzustellen. Lassen Sie uns loslegen!
Schritt 1: Erstellen der Anzeigeschnittstelle
Dieses Tutorial besteht aus einer einzelnen Seite, die in zwei Regionen unterteilt ist: einen Anzeigebereich und einen Einfügebereich. Die Anzeigeoberfläche, die wir in diesem Schritt erstellen, zeigt die Produkte in einer GridView an und enthält eine Schaltfläche mit dem Titel Produktversand verarbeiten. Wenn auf diese Schaltfläche geklickt wird, wird die Anzeigeschnittstelle durch die Einfügeschnittstelle ersetzt, die in Abbildung 1 dargestellt ist. Die Anzeigeoberfläche wird zurückgegeben, nachdem auf die Schaltflächen Produkte aus Versand hinzufügen oder Abbrechen geklickt wurden. Wir erstellen die Einfügeschnittstelle in Schritt 2.
Beim Erstellen einer Seite mit zwei Schnittstellen, von denen jeweils nur eine sichtbar ist, wird jede Schnittstelle in der Regel in einem Panel-Websteuerelement platziert, das als Container für andere Steuerelemente dient. Daher verfügt unsere Seite über zwei Panel-Steuerelemente, eines für jede Schnittstelle.
Öffnen Sie zunächst die BatchInsert.aspx
Seite im BatchData
Ordner, und ziehen Sie ein Panel aus der Toolbox auf die Designer (siehe Abbildung 2). Legen Sie die Panel-Eigenschaft auf ID
fest DisplayInterface
. Beim Hinzufügen des Bereichs zum Designer werden dessen Height
Eigenschaften und Width
auf 50px bzw. 125px festgelegt. Löschen Sie diese Eigenschaftswerte aus dem Eigenschaftenfenster.
Abbildung 2: Ziehen Eines Bereichs aus der Toolbox auf die Designer (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Ziehen Sie als Nächstes ein Button- und GridView-Steuerelement in das Panel. Legen Sie die Button-Eigenschaft ID
auf ProcessShipment
und ihre Text
Eigenschaft auf Produktversand verarbeiten fest. Legen Sie die GridView-Eigenschaft ID
auf ProductsGrid
fest, und binden Sie sie über das Smarttag an eine neue ObjectDataSource mit dem Namen ProductsDataSource
. Konfigurieren Sie die ObjectDataSource so, dass ihre Daten aus der s-Methode der ProductsBLL
Klasse GetProducts
abgerufen werden. Da diese GridView nur zum Anzeigen von Daten verwendet wird, legen Sie die Dropdownlisten in den Registerkarten UPDATE, INSERT und DELETE auf (Keine) fest. Klicken Sie auf Fertig stellen, um den Assistenten zum Konfigurieren von Datenquellen abzuschließen.
Abbildung 3: Anzeigen der von der ProductsBLL
Class s-Methode GetProducts
zurückgegebenen Daten (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
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 ObjectDataSource-Assistenten fügt Visual Studio BoundFields und ein CheckBoxField für die Produktdatenfelder hinzu. Entfernen Sie alle Felder außer ProductName
, CategoryName
, SupplierName
, UnitPrice
und Discontinued
. Fühlen Sie sich frei, ästhetische Anpassungen vorzunehmen. Ich entschloss mich, das UnitPrice
Feld als Währungswert zu formatieren, die Felder neu anzuordnen und einige der Feldwerte HeaderText
umzubenennen. Konfigurieren Sie gridView auch so, dass es Paging- und Sortierunterstützung enthält, indem Sie die Kontrollkästchen Paging aktivieren und Sortierung aktivieren im Smarttag von GridView aktivieren.
Nachdem Sie die Steuerelemente Panel, Button, GridView und ObjectDataSource hinzugefügt und die GridView-Felder angepasst haben, sollte das deklarative Markup Ihrer Seite wie folgt aussehen:
<asp:Panel ID="DisplayInterface" runat="server">
<p>
<asp:Button ID="ProcessShipment" runat="server"
Text="Process Product Shipment" />
</p>
<asp:GridView ID="ProductsGrid" runat="server" AllowPaging="True"
AllowSorting="True" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsDataSource">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True" SortExpression="SupplierName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False"
SortExpression="UnitPrice">
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued">
<ItemStyle HorizontalAlign="Center" />
</asp:CheckBoxField>
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
</asp:Panel>
Beachten Sie, dass das Markup für Button und GridView in den öffnenden und schließenden <asp:Panel>
Tags angezeigt wird. Da sich diese Steuerelemente innerhalb des DisplayInterface
Bereichs befinden, können wir sie ausblenden, indem wir einfach die Eigenschaft panel s Visible
auf False
festlegen. Schritt 3 befasst sich mit der programmgesteuerten Änderung der Panel-Eigenschaft Visible
als Reaktion auf einen Schaltflächenklick, um eine Schnittstelle anzuzeigen, während die andere ausgeblendet wird.
Nehmen Sie sich einen Moment Zeit, um unseren Fortschritt über einen Browser anzuzeigen. Wie in Abbildung 5 dargestellt, sollte über einer GridView die Schaltfläche Produktversand verarbeiten angezeigt werden, in der die Produkte gleichzeitig aufgeführt sind.
Abbildung 5: Die GridView-Listen die Sortierungs- und Pagingfunktionen für Produkte und Angebote (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Schritt 2: Erstellen der Einfügeschnittstelle
Nachdem die Anzeigeoberfläche abgeschlossen ist, können Sie die Einfügeschnittstelle erstellen. In diesem Tutorial erstellen wir eine Einfügeschnittstelle, die zur Eingabe eines einzelnen Lieferanten- und Kategoriewerts auffordert und dem Benutzer dann ermöglicht, bis zu fünf Produktnamen und Einzelpreiswerte einzugeben. Mit dieser Benutzeroberfläche kann der Benutzer ein bis fünf neue Produkte hinzufügen, die alle die gleiche Kategorie und denselben Lieferanten haben, aber eindeutige Produktnamen und Preise haben.
Ziehen Sie zunächst ein Panel aus der Toolbox auf die Designer, und platzieren Sie es unter dem vorhandenen DisplayInterface
Panel. Legen Sie die ID
-Eigenschaft dieses neu hinzugefügten Panel auf InsertingInterface
fest, und legen Sie die - Visible
Eigenschaft auf fest False
. Wir fügen Code hinzu, der die InsertingInterface
Panel-Eigenschaft Visible
in Schritt 3 auf True
festlegt. Löschen Sie außerdem die Werte der Panel- Height
und Width
-Eigenschaft.
Als Nächstes müssen wir die Einfügeschnittstelle erstellen, die in Abbildung 1 gezeigt wurde. Diese Schnittstelle kann mit einer Vielzahl von HTML-Techniken erstellt werden, aber wir verwenden eine recht einfache: eine tabelle mit vier Spalten und sieben Zeilen.
Hinweis
Wenn ich Markup für HTML-Elemente <table>
einarbeite, verwende ich lieber die Quellansicht. Visual Studio verfügt zwar über Tools zum Hinzufügen von <table>
Elementen über die Designer, die Designer scheint jedoch nur allzu bereit zu sein, einstellungen ungefragt style
in das Markup einzufügen. Nachdem ich das <table>
Markup erstellt habe, kehren Sie in der Regel zum Designer zurück, um die Websteuerelemente hinzuzufügen und deren Eigenschaften festzulegen. Beim Erstellen von Tabellen mit vordefinierten Spalten und Zeilen bevorzuge ich die Verwendung von statischem HTML anstelle des Table Web-Steuerelements , da auf alle Websteuerelemente, die in einem Table Web-Steuerelement platziert werden, nur mit dem FindControl("controlID")
Muster zugegriffen werden kann. Ich verwende jedoch Tabellenwebsteuerelemente für Tabellen mit dynamischer Größe (solche, deren Zeilen oder Spalten auf bestimmten Datenbank- oder benutzerspezifischen Kriterien basieren), da das Table Web-Steuerelement programmgesteuert erstellt werden kann.
Geben Sie das folgende Markup in die <asp:Panel>
Tags des InsertingInterface
Bereichs ein:
<table class="DataWebControlStyle" cellspacing="0">
<tr class="BatchInsertHeaderRow">
<td class="BatchInsertLabel">Supplier:</td>
<td></td>
<td class="BatchInsertLabel">Category:</td>
<td></td>
</tr>
<tr class="BatchInsertRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertAlternatingRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertAlternatingRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertFooterRow">
<td colspan="4">
</td>
</tr>
</table>
Dieses <table>
Markup enthält noch keine Websteuerelemente, wir fügen diese vorübergehend hinzu. Beachten Sie, dass jedes <tr>
Element eine bestimmte CSS-Klasseneinstellung enthält: BatchInsertHeaderRow
für die Kopfzeile, in die die DropDownLists des Lieferanten und der Kategorie eingefügt werden, BatchInsertFooterRow
für die Fußzeile, in die die Schaltflächen "Produkte aus Sendung hinzufügen" und "Abbrechen" wechseln, und abwechselnd BatchInsertRow
und BatchInsertAlternatingRow
werte für die Zeilen, die die TextBox-Steuerelemente für Produkt und Einheit enthalten. Ich habe entsprechende CSS-Klassen in der Styles.css
Datei erstellt, um der Einfügeschnittstelle ein ähnliches Aussehen wie die GridView- und DetailsView-Steuerelemente zu verleihen, die wir in diesen Tutorials verwendet haben. Diese CSS-Klassen werden unten gezeigt.
/*** Styles for ~/BatchData/BatchInsert.aspx tutorial ***/
.BatchInsertLabel
{
font-weight: bold;
text-align: right;
}
.BatchInsertHeaderRow td
{
color: White;
background-color: #900;
padding: 11px;
}
.BatchInsertFooterRow td
{
text-align: center;
padding-top: 5px;
}
.BatchInsertRow
{
}
.BatchInsertAlternatingRow
{
background-color: #fcc;
}
Kehren Sie nach Eingabe dieses Markups zur Entwurfsansicht zurück. Dies <table>
sollte im Designer als tabelle mit vier Spalten und sieben Zeilen angezeigt werden, wie in Abbildung 6 dargestellt.
Abbildung 6: Die Einfügeschnittstelle besteht aus einer vierspaltigen, Seven-Row Tabelle (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Wir sind jetzt bereit, die Websteuerelemente der Einfügeschnittstelle hinzuzufügen. Ziehen Sie zwei DropDownLists aus der Toolbox in die entsprechenden Zellen in der ersten Tabelle für den Lieferanten und eine für die Kategorie.
Legen Sie die DropDownList-Eigenschaft ID
des Lieferanten auf fest Suppliers
, und binden Sie sie an eine neue ObjectDataSource mit dem Namen SuppliersDataSource
. Konfigurieren Sie die neue ObjectDataSource so, dass ihre Daten aus der SuppliersBLL
Klasse s-Methode GetSuppliers
abgerufen werden, und legen Sie die Dropdownliste UPDATE-Registerkarten auf (None) fest. Klicken Sie auf Fertig stellen, um den Assistenten abzuschließen.
Abbildung 7: Konfigurieren der ObjectDataSource für die Verwendung der SuppliersBLL
Class s-Methode (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)GetSuppliers
Lassen Sie dropDownList Suppliers
das CompanyName
Datenfeld anzeigen und das SupplierID
Datenfeld als s-Werte ListItem
verwenden.
Abbildung 8: Anzeigen des CompanyName
Datenfelds und Verwenden SupplierID
als Wert (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Benennen Sie die zweite DropDownList, Categories
und binden Sie sie an eine neue ObjectDataSource namens CategoriesDataSource
. Konfigurieren Sie objectDataSource CategoriesDataSource
für die Verwendung der CategoriesBLL
Klasse s GetCategories
. Legen Sie die Dropdownlisten auf den Registerkarten UPDATE und DELETE auf (Keine) fest, und klicken Sie auf Fertig stellen, um den Assistenten abzuschließen. Lassen Sie schließlich das Datenfeld in DropDownList anzeigen CategoryName
, und verwenden Sie als CategoryID
Wert.
Nachdem diese beiden DropDownLists hinzugefügt und an entsprechend konfigurierte ObjectDataSources gebunden wurden, sollte der Bildschirm ähnlich wie Abbildung 9 aussehen.
Abbildung 9: Die Kopfzeile enthält jetzt die Suppliers
DropDownLists und Categories
(Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Wir müssen jetzt die TextBoxes erstellen, um den Namen und den Preis für jedes neue Produkt zu erfassen. Ziehen Sie ein TextBox-Steuerelement aus der Toolbox auf die Designer für jede der fünf Produktnamen- und Preiszeilen. Legen Sie die ID
Eigenschaften der TextBoxes auf ProductName1
, UnitPrice1
, ProductName2
UnitPrice2
, ProductName3
, UnitPrice3
, usw. fest.
Fügen Sie einen CompareValidator nach den TextBoxen pro Preiseinheit hinzu, und legen Sie die ControlToValidate
-Eigenschaft auf die entsprechende ID
fest. Legen Sie außerdem die Operator
-Eigenschaft auf GreaterThanEqual
, ValueToCompare
auf 0 und Type
auf fest Currency
. Diese Einstellungen weisen den CompareValidator an, sicherzustellen, dass der Preis bei Eingabe ein gültiger Währungswert ist, der größer oder gleich Null ist. Legen Sie die Text
-Eigenschaft auf * und ErrorMessage
auf Der Preis muss größer oder gleich 0 sein. Lassen Sie außerdem alle Währungssymbole aus.
Hinweis
Die Einfügeschnittstelle enthält keine RequiredFieldValidator-Steuerelemente, obwohl das ProductName
Feld in der Products
Datenbanktabelle keine Werte zulässt NULL
. Dies liegt daran, dass der Benutzer bis zu fünf Produkte eingeben soll. Wenn der Benutzer beispielsweise den Produktnamen und den Einzelpreis für die ersten drei Zeilen angeben und die letzten beiden Zeilen leer lassen würde, würden wir dem System einfach drei neue Produkte hinzufügen. Da ProductName
erforderlich ist, müssen wir jedoch programmgesteuert überprüfen, ob bei Eingabe eines Preises pro Einheit ein entsprechender Produktnamenswert angegeben wird. Diese Überprüfung wird in Schritt 4 behandelt.
Beim Überprüfen der Benutzereingabe meldet CompareValidator ungültige Daten, wenn der Wert ein Währungssymbol enthält. Fügen Sie vor jedem TextBox-Element des Einzelpreises ein $ hinzu, um als visueller Hinweis zu dienen, der den Benutzer anweist, das Währungssymbol bei der Preiseingabe wegzulassen.
Fügen Sie schließlich im InsertingInterface
Panel ein ValidationSummary-Steuerelement hinzu, und legen die ShowMessageBox
-Eigenschaft auf True
und die ShowSummary
-Eigenschaft auf False
fest. Wenn der Benutzer bei diesen Einstellungen einen ungültigen Wert für den Einzelpreis eingibt, wird neben den beleidigenden TextBox-Steuerelementen ein Sternchen angezeigt, und validationSummary zeigt ein clientseitiges Meldungsfeld an, das die zuvor angegebene Fehlermeldung anzeigt.
An diesem Punkt sollte der Bildschirm ähnlich wie In Abbildung 10 aussehen.
Abbildung 10: Die Einfügeschnittstelle enthält jetzt TextBoxes für die Produktnamen und -preise (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Als Nächstes müssen wir der Fußzeile die Schaltflächen Produkte aus Versand hinzufügen und Abbrechen hinzufügen. Ziehen Sie zwei Schaltflächen-Steuerelemente aus der Toolbox in die Fußzeile der Einfügeschnittstelle, und legen Sie die Eigenschaften Schaltflächen ID
auf AddProducts
und CancelButton
und auf Text
Produkte aus Versand hinzufügen bzw. Abbrechen fest. Legen Sie außerdem die -Eigenschaft des CancelButton
Steuerelements CausesValidation
auf fest false
.
Schließlich müssen wir ein Label Web-Steuerelement hinzufügen, das status Nachrichten für die beiden Schnittstellen anzeigt. Wenn ein Benutzer beispielsweise erfolgreich eine neue Lieferung von Produkten hinzufügt, möchten wir zur Anzeigeoberfläche zurückkehren und eine Bestätigungsmeldung anzeigen. Wenn der Benutzer jedoch einen Preis für ein neues Produkt angibt, aber den Produktnamen auslässt, müssen wir eine Warnmeldung anzeigen, da das ProductName
Feld erforderlich ist. Da diese Meldung für beide Schnittstellen angezeigt werden soll, platzieren Sie sie oben auf der Seite außerhalb der Bereiche.
Ziehen Sie ein Label Web-Steuerelement aus der Toolbox an den Anfang der Seite im Designer. Legen Sie die ID
-Eigenschaft auf StatusLabel
fest, löschen Sie die Text
-Eigenschaft, und legen Sie die Visible
Eigenschaften und EnableViewState
auf fest False
. Wie wir in den vorherigen Tutorials gesehen haben, ermöglicht das Festlegen der EnableViewState
Eigenschaft aufFalse
, die Eigenschaftswerte von Label programmgesteuert zu ändern und sie automatisch auf die Standardwerte für das nachfolgende Postback rückgängig machen. Dies vereinfacht den Code zum Anzeigen einer status Nachricht als Reaktion auf eine Benutzeraktion, die beim nachfolgenden Postback nicht mehr angezeigt wird. Legen Sie schließlich die StatusLabel
Eigenschaft des Steuerelements CssClass
auf Warning fest. Dies ist der Name einer CSS-Klasse, die in Styles.css
definiert ist, die Text in einer großen, kursiven, fetten, roten Schriftart anzeigt.
Abbildung 11 zeigt die Visual Studio-Designer, nachdem die Bezeichnung hinzugefügt und konfiguriert wurde.
Abbildung 11: Platzieren Sie das StatusLabel
Steuerelement über den Zwei-Panel-Steuerelementen (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Schritt 3: Wechseln zwischen der Anzeige- und der Einfügeschnittstelle
An diesem Punkt haben wir das Markup für unsere Anzeige- und Einfügeschnittstellen abgeschlossen, aber wir haben noch zwei Aufgaben:
- Wechseln zwischen anzeige- und einfügeschnittstellen
- Hinzufügen der Produkte in der Sendung zur Datenbank
Derzeit ist die Anzeigeschnittstelle sichtbar, aber die Einfügeschnittstelle ist ausgeblendet. Dies liegt daran, dass die DisplayInterface
Panel-Eigenschaft Visible
auf True
(der Standardwert) festgelegt ist, während die InsertingInterface
Panel-Eigenschaft auf False
Visible
festgelegt ist. Um zwischen den beiden Schnittstellen zu wechseln, müssen wir lediglich den Eigenschaftswert jedes Steuerelements Visible
umschalten.
Wir möchten von der Anzeigeschnittstelle zur Einfügeschnittstelle wechseln, wenn auf die Schaltfläche Produktversand verarbeiten geklickt wird. Erstellen Sie daher einen Ereignishandler für dieses Button-Ereignis Click
, das den folgenden Code enthält:
Protected Sub ProcessShipment_Click(sender As Object, e As EventArgs) _
Handles ProcessShipment.Click
DisplayInterface.Visible = False
InsertingInterface.Visible = True
End Sub
Dieser Code blendet einfach den DisplayInterface
Bereich aus und zeigt den InsertingInterface
Bereich an.
Erstellen Sie als Nächstes Ereignishandler für die Steuerelemente Add Products from Shipment und Cancel Button in der Einfügeschnittstelle. Wenn auf eine dieser Schaltflächen geklickt wird, müssen wir zurück zur Anzeigeoberfläche rückgängig machen. Erstellen Sie Click
Ereignishandler für beide Button-Steuerelemente, sodass sie aufrufen ReturnToDisplayInterface
, eine Methode, die wir vorübergehend hinzufügen. Zusätzlich zum Ausblenden des InsertingInterface
Bereichs und anzeigen des DisplayInterface
Bereichs muss die ReturnToDisplayInterface
-Methode die Websteuerelemente in ihren Vorbearbeitungszustand zurückgeben. Dies umfasst das Festlegen der DropDownLists-Eigenschaften SelectedIndex
auf 0 und das Löschen der Text
Eigenschaften der TextBox-Steuerelemente.
Hinweis
Überlegen Sie, was passieren könnte, wenn wir die Steuerelemente nicht in den Zustand vor der Bearbeitung zurückgesetzt haben, bevor sie zur Anzeigeschnittstelle zurückkehren. Ein Benutzer kann auf die Schaltfläche Produktversand verarbeiten klicken, die Produkte aus der Sendung eingeben und dann auf Produkte aus Sendung hinzufügen klicken. Dadurch würden die Produkte hinzugefügt und der Benutzer wieder zur Anzeigeoberfläche zurückkehren. An diesem Punkt möchte der Benutzer möglicherweise eine weitere Sendung hinzufügen. Wenn sie auf die Schaltfläche Produktversand verarbeiten klicken, kehren sie zur Einfügeschnittstelle zurück, aber die DropDownList-Auswahlen und TextBox-Werte würden weiterhin mit ihren vorherigen Werten aufgefüllt.
Protected Sub AddProducts_Click(sender As Object, e As EventArgs) _
Handles AddProducts.Click
' TODO: Save the products
' Revert to the display interface
ReturnToDisplayInterface()
End Sub
Protected Sub CancelButton_Click(sender As Object, e As EventArgs) _
Handles CancelButton.Click
' Revert to the display interface
ReturnToDisplayInterface()
End Sub
Const firstControlID As Integer = 1
Const lastControlID As Integer = 5
Private Sub ReturnToDisplayInterface()
' Reset the control values in the inserting interface
Suppliers.SelectedIndex = 0
Categories.SelectedIndex = 0
For i As Integer = firstControlID To lastControlID
CType(InsertingInterface.FindControl _
("ProductName" + i.ToString()), TextBox).Text = String.Empty
CType(InsertingInterface.FindControl _
("UnitPrice" + i.ToString()), TextBox).Text = String.Empty
Next
DisplayInterface.Visible = True
InsertingInterface.Visible = False
End Sub
Beide Click
Ereignishandler rufen einfach die ReturnToDisplayInterface
-Methode auf, obwohl wir in Schritt 4 zum Ereignishandler Add Products from Shipment Click
zurückkehren und Code hinzufügen, um die Produkte zu speichern. ReturnToDisplayInterface
beginnt, indem die Suppliers
DropDownLists und Categories
die DropDownLists zu ihren ersten Optionen zurückgegeben werden. Die beiden Konstanten und lastControlID
markieren die Anfangs- und End-Steuerelementindexwerte, die zum Benennen des Produktnamens firstControlID
und des Einzelpreises TextBoxes in der Einfügeschnittstelle verwendet werden, und werden in den Begrenzungen der For
Schleife verwendet, die die Text
Eigenschaften der TextBox-Steuerelemente wieder auf eine leere Zeichenfolge festlegt. Schließlich werden die Panel-Eigenschaften Visible
zurückgesetzt, sodass die Einfügeschnittstelle ausgeblendet und die Anzeigeschnittstelle angezeigt wird.
Nehmen Sie sich einen Moment Zeit, um diese Seite in einem Browser zu testen. Beim ersten Besuch der Seite sollte die Anzeigeoberfläche angezeigt werden, wie in Abbildung 5 dargestellt. Klicken Sie auf die Schaltfläche Produktversand verarbeiten. Die Seite wird postbacken, und Sie sollten nun die Einfügeschnittstelle sehen, wie in Abbildung 12 dargestellt. Durch Klicken auf die Schaltflächen Produkte aus Versand hinzufügen oder Abbrechen kehren Sie zur Anzeigeoberfläche zurück.
Hinweis
Nehmen Sie sich beim Anzeigen der Einfügeschnittstelle einen Moment Zeit, um die CompareValidators für die TextBoxen pro Preiseinheit zu testen. Wenn Sie auf die Schaltfläche Produkte vom Versand hinzufügen mit ungültigen Währungswerten oder Preisen mit einem Wert kleiner als 0 (Null) klicken, sollte eine clientseitige Meldung angezeigt werden.
Abbildung 12: Die Einfügeschnittstelle wird angezeigt, nachdem Sie auf die Schaltfläche "Produktversand verarbeiten" geklickt haben (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)
Schritt 4: Hinzufügen der Produkte
Für dieses Tutorial bleibt nur noch das Speichern der Produkte in der Datenbank im Ereignishandler Add Products from Shipment Button des -Ereignishandlers Click
. Dies kann erreicht werden, indem Sie ein ProductsDataTable
erstellen und für jeden der angegebenen Produktnamen eine ProductsRow
instance hinzufügen. Nachdem diese ProductsRow
hinzugefügt wurden, führen wir einen Aufruf der ProductsBLL
-Klasse s-Methode UpdateWithTransaction
durch, die das ProductsDataTable
-Objekt übergibt. Denken Sie daran, dass die UpdateWithTransaction
-Methode, die im Tutorial Wrapping Database Modifications innerhalb eines Transaction-Tutorials erstellt wurde, an ProductsDataTable
die -Methode von ProductsTableAdapter
UpdateWithTransaction
übergibt. Von dort aus wird eine ADO.NET Transaktion gestartet, und der TableAdapter gibt eine INSERT
Anweisung an die Datenbank für jede in der DataTable hinzugefügte ProductsRow
Aus. Wenn alle Produkte ohne Fehler hinzugefügt werden, wird für die Transaktion ein Commit ausgeführt, andernfalls wird ein Rollback ausgeführt.
Der Code für den Ereignishandler der Schaltfläche "Produkte aus Sendung hinzufügen Click
" muss ebenfalls eine Fehlerüberprüfung durchführen. Da in der Einfügeschnittstelle keine RequiredFieldValidators verwendet werden, kann ein Benutzer einen Preis für ein Produkt eingeben, während er seinen Namen auslässt. Da der Name des Produkts erforderlich ist, müssen wir bei einer solchen Bedingung den Benutzer warnen und nicht mit den Einfügungen fortfahren. Der vollständige Click
Ereignishandlercode folgt:
Protected Sub AddProducts_Click(sender As Object, e As EventArgs) _
Handles AddProducts.Click
' Make sure that the UnitPrice CompareValidators report valid data...
If Not Page.IsValid Then Exit Sub
' Add new ProductsRows to a ProductsDataTable...
Dim products As New Northwind.ProductsDataTable()
For i As Integer = firstControlID To lastControlID
' Read in the values for the product name and unit price
Dim productName As String = CType(InsertingInterface.FindControl _
("ProductName" + i.ToString()), TextBox).Text.Trim()
Dim unitPrice As String = CType(InsertingInterface.FindControl _
("UnitPrice" + i.ToString()), TextBox).Text.Trim()
' Ensure that if unitPrice has a value, so does productName
If unitPrice.Length > 0 AndAlso productName.Length = 0 Then
' Display a warning and exit this event handler
StatusLabel.Text = "If you provide a unit price you must also
include the name of the product."
StatusLabel.Visible = True
Exit Sub
End If
' Only add the product if a product name value is provided
If productName.Length > 0 Then
' Add a new ProductsRow to the ProductsDataTable
Dim newProduct As Northwind.ProductsRow = products.NewProductsRow()
' Assign the values from the web page
newProduct.ProductName = productName
newProduct.SupplierID = Convert.ToInt32(Suppliers.SelectedValue)
newProduct.CategoryID = Convert.ToInt32(Categories.SelectedValue)
If unitPrice.Length > 0 Then
newProduct.UnitPrice = Convert.ToDecimal(unitPrice)
End If
' Add any "default" values
newProduct.Discontinued = False
newProduct.UnitsOnOrder = 0
products.AddProductsRow(newProduct)
End If
Next
' If we reach here, see if there were any products added
If products.Count > 0 Then
' Add the new products to the database using a transaction
Dim productsAPI As New ProductsBLL()
productsAPI.UpdateWithTransaction(products)
' Rebind the data to the grid so that the products just added are displayed
ProductsGrid.DataBind()
' Display a confirmation (don't use the Warning CSS class, though)
StatusLabel.CssClass = String.Empty
StatusLabel.Text = String.Format( _
"{0} products from supplier {1} have been " & _
"added and filed under category {2}.", _
products.Count, Suppliers.SelectedItem.Text, Categories.SelectedItem.Text)
StatusLabel.Visible = True
' Revert to the display interface
ReturnToDisplayInterface()
Else
' No products supplied!
StatusLabel.Text =
"No products were added. Please enter the " & _
"product names and unit prices in the textboxes."
StatusLabel.Visible = True
End If
End Sub
Der Ereignishandler stellt zunächst sicher, dass die Page.IsValid
-Eigenschaft den Wert zurückgibt True
. Wenn zurückgegeben wird False
, bedeutet dies, dass mindestens einer der CompareValidators ungültige Daten meldet. In einem solchen Fall möchten wir nicht versuchen, die eingegebenen Produkte einzufügen, oder es kommt zu einer Ausnahme, wenn versucht wird, den vom Benutzer eingegebenen Einzelpreiswert der ProductsRow
s-Eigenschaft UnitPrice
zuzuweisen.
Als Nächstes wird eine neue ProductsDataTable
instance erstellt (products
). Eine For
Schleife wird verwendet, um textBoxes des Produktnamens und des Einzelpreises zu durchlaufen, und die Text
Eigenschaften werden in die lokalen Variablen productName
und unitPrice
gelesen. Wenn der Benutzer einen Wert für den Einzelpreis, aber nicht für den entsprechenden Produktnamen eingegeben hat, StatusLabel
wird die Meldung Wenn Sie einen Einzelpreis angeben, müssen Sie auch den Namen des Produkts angeben, und der Ereignishandler wird beendet.
Wenn ein Produktname angegeben wurde, wird mit der ProductsDataTable
s-Methode NewProductsRow
eine neue ProductsRow
instance erstellt. Diese neue ProductsRow
instance -ProductName
Eigenschaft wird auf den aktuellen Produktnamen TextBox festgelegt, während die SupplierID
Eigenschaften und CategoryID
den SelectedValue
Eigenschaften der DropDownLists im Header der Einfügungsschnittstelle zugewiesen sind. Wenn der Benutzer einen Wert für den Produktpreis eingegeben hat, wird er der ProductsRow
eigenschaft instance s UnitPrice
zugewiesen. Andernfalls bleibt die Eigenschaft nicht zugewiesen, was zu einem NULL
Wert für UnitPrice
in der Datenbank führt. Schließlich werden die Discontinued
Eigenschaften und UnitsOnOrder
den hartcodierten Werten False
bzw. 0 zugewiesen.
Nachdem die Eigenschaften dem ProductsRow
instance werden sie dem ProductsDataTable
hinzugefügt.
Nach Abschluss der For
Schleife überprüfen wir, ob Produkte hinzugefügt wurden. Der Benutzer kann schließlich auf Produkte vom Versand hinzufügen geklickt haben, bevor er Produktnamen oder Preise eingibt. Wenn mindestens ein Produkt in ProductsDataTable
vorhanden ist, wird die -Methode der ProductsBLL
Klasse s UpdateWithTransaction
aufgerufen. Als Nächstes werden die Daten an die ProductsGrid
GridView-Instanz übergeben, sodass die neu hinzugefügten Produkte in der Anzeigeschnittstelle angezeigt werden. Der StatusLabel
wird aktualisiert, um eine Bestätigungsmeldung anzuzeigen, und das ReturnToDisplayInterface
wird aufgerufen, wobei die einfüge-Schnittstelle ausgeblendet und die Anzeigeschnittstelle angezeigt wird.
Wenn keine Produkte eingegeben wurden, bleibt die Einfügeschnittstelle angezeigt, aber die Meldung Keine Produkte wurden hinzugefügt. Geben Sie die Produktnamen und Einzelpreise in die Textfelder ein.
Abbildungen 13, 14 und 15 zeigen die Einfüge- und Anzeigeschnittstellen in Aktion. In Abbildung 13 hat der Benutzer einen Einzelpreiswert ohne entsprechenden Produktnamen eingegeben. Abbildung 14 zeigt die Anzeigeschnittstelle, nachdem drei neue Produkte erfolgreich hinzugefügt wurden, während Abbildung 15 zwei der neu hinzugefügten Produkte in GridView zeigt (das dritte auf der vorherigen Seite).
Abbildung 13: Bei der Eingabe eines Einzelpreises ist ein Produktname erforderlich (Klicken Sie hier, um das bild in voller Größe anzuzeigen)
Abbildung 14: Drei neue Gemüse wurden für den Lieferanten Mayumi hinzugefügt (Klicken Sie, um das Bild in voller Größe anzuzeigen)
Abbildung 15: Die neuen Produkte finden Sie auf der letzten Seite der GridView (Klicken Sie hier, um das bild in voller Größe anzuzeigen)
Hinweis
Die in diesem Tutorial verwendete Batcheinfügungslogik umschließt die Einfügevorgänge innerhalb des Transaktionsbereichs. Um dies zu überprüfen, führen Sie gezielt einen Fehler auf Datenbankebene ein. Anstatt z. B. die neue ProductsRow
instance-Eigenschaft CategoryID
dem ausgewählten Wert in der Categories
DropDownList zuzuweisen, weisen Sie ihn einem Wert wie i * 5
zu. Hier i
ist der Schleifenindexer mit Werten zwischen 1 und 5. Daher hat das erste Produkt beim Hinzufügen von zwei oder mehr Produkten in der Batcheinfügung einen gültigen CategoryID
Wert (5), aber nachfolgende Produkte verfügen über CategoryID
Werte, die nicht mit CategoryID
Werten in der Categories
Tabelle übereinstimmen. Der Nettoeffekt ist, dass die erste INSERT
erfolgreich ist, die nachfolgenden mit einer Verletzung der Fremdschlüsseleinschränkung fehlschlagen. Da der Batcheinfügung atomisch ist, wird das erste INSERT
Rollback ausgeführt, wodurch die Datenbank in den Zustand zurückgesetzt wird, bevor der Batcheinfügeprozess gestartet wurde.
Zusammenfassung
In diesem und den beiden vorherigen Tutorials haben wir Schnittstellen zum Aktualisieren, Löschen und Einfügen von Datenbatches erstellt, die alle die Transaktionsunterstützung verwendet haben, die wir der Datenzugriffsebene im Tutorial Wrapping Database Modifications in a Transaction hinzugefügt haben. In bestimmten Szenarien verbessern solche Benutzeroberflächen für die Batchverarbeitung die Effizienz des Endbenutzers erheblich, indem sie die Anzahl der Klicks, Postbacks und Kontextwechsel zwischen Tastatur und Maus verringert und gleichzeitig die Integrität der zugrunde liegenden Daten beibehalten.
Dieses Tutorial vervollständigen unseren Blick auf die Arbeit mit Batchdaten. Die nächsten Tutorials untersuchen eine Vielzahl erweiterter Szenarien auf Datenzugriffsebene, einschließlich der Verwendung gespeicherter Prozeduren in den TableAdapter-Methoden, konfigurieren von Einstellungen auf Verbindungs- und Befehlsebene in der DAL, Verschlüsseln von Verbindungszeichenfolgen und vieles mehr!
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 Stunden. Er kann unter mitchell@4GuysFromRolla.comoder über seinen Blog erreicht werden, der unter http://ScottOnWriting.NETzu finden ist.
Besonderen Dank an
Diese Tutorialreihe wurde von vielen hilfreichen Prüfern überprüft. Leitende Gutachter für dieses Tutorial waren Hilton Giesenow und S ren Jacob Lauritsen. Möchten Sie meine anstehenden MSDN-Artikel lesen? Wenn dies der Fall ist, legen Sie eine Zeile unter abmitchell@4GuysFromRolla.com.