Share via


Einfügen in Batches (C#)

von Scott Mitchell

PDF herunterladen

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.

Die Batcheinfügungsschnittstelle

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.

Ziehen Sie ein Panel aus der Toolbox auf die Designer

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.

Anzeigen der von der GetProducts-Methode der ProductsBLL-Klasse zurückgegebenen Daten

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)

Legen Sie die Drop-Down Listen in den Registerkarten UPDATE, INSERT und DELETE auf (Keine) fest.

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, UnitPriceund 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 falsefestlegen. 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.

GridView Listen die Sortier- und Pagingfunktionen für Produkte und Angebote

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.

Die Einfügeschnittstelle besteht aus einer vierspaltigen, Seven-Row Tabelle.

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.

Konfigurieren der ObjectDataSource für die Verwendung der GetSuppliers-Methode der SuppliersBLL-Klasse

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.

Anzeigen des CompanyName-Datenfelds und Verwenden von SupplierID als Wert

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.

Die Kopfzeile enthält jetzt die DropDownLists für Lieferanten und Kategorien.

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, ProductName2UnitPrice2, ProductName3, UnitPrice3, usw. fest.

Fügen Sie einen CompareValidator nach den TextBoxen pro Preiseinheit hinzu, und legen Sie die ControlToValidate -Eigenschaft auf die entsprechende IDfest. 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 falsefest. 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.

Die Einfügeschnittstelle enthält jetzt TextBoxes für die Produktnamen und -preise.

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 StatusLabelfest, 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.

Platzieren Sie das StatusLabel-Steuerelement über den beiden Panel-Steuerelementen.

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 falseVisible 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 void ProcessShipment_Click(object sender, EventArgs e)
{
    DisplayInterface.Visible = false;
    InsertingInterface.Visible = true;
}

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 void AddProducts_Click(object sender, EventArgs e)
{
    // TODO: Save the products
    // Revert to the display interface
    ReturnToDisplayInterface();
}
protected void CancelButton_Click(object sender, EventArgs e)
{
    // Revert to the display interface
    ReturnToDisplayInterface();
}
const int firstControlID = 1;
const int lastControlID = 5;
private void ReturnToDisplayInterface()
{
    // Reset the control values in the inserting interface
    Suppliers.SelectedIndex = 0;
    Categories.SelectedIndex = 0;
    for (int i = firstControlID; i <= lastControlID; i++)
    {
        ((TextBox)InsertingInterface.FindControl("ProductName" + i.ToString())).Text =
            string.Empty;
        ((TextBox)InsertingInterface.FindControl("UnitPrice" + i.ToString())).Text = 
            string.Empty;
    }
    DisplayInterface.Visible = true;
    InsertingInterface.Visible = false;
}

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.

Die Einfügeschnittstelle wird angezeigt, nachdem Sie auf die Schaltfläche

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 ProductsTableAdapter s-Methode 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 void AddProducts_Click(object sender, EventArgs e)
{
    // Make sure that the UnitPrice CompareValidators report valid data...
    if (!Page.IsValid)
        return;
    // Add new ProductsRows to a ProductsDataTable...
    Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
    for (int i = firstControlID; i <= lastControlID; i++)
    {
        // Read in the values for the product name and unit price
        string productName = ((TextBox)InsertingInterface.FindControl
            ("ProductName" + i.ToString())).Text.Trim();
        string unitPrice = ((TextBox)InsertingInterface.FindControl
            ("UnitPrice" + i.ToString())).Text.Trim();
        // Ensure that if unitPrice has a value, so does productName
        if (unitPrice.Length > 0 && productName.Length == 0)
        {
            // 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;
            return;
        }
        // Only add the product if a product name value is provided
        if (productName.Length > 0)
        {
            // Add a new ProductsRow to the ProductsDataTable
            Northwind.ProductsRow newProduct = 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)
                newProduct.UnitPrice = Convert.ToDecimal(unitPrice);
            // Add any "default" values
            newProduct.Discontinued = false;
            newProduct.UnitsOnOrder = 0;
            products.AddProductsRow(newProduct);
        }
    }
    // If we reach here, see if there were any products added
    if (products.Count > 0)
    {
        // Add the new products to the database using a transaction
        ProductsBLL productsAPI = 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;
    }
}

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 unitPricegelesen. 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 -ProductNameEigenschaft 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 ProductsDataTablehinzugefü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 ProductsDataTablevorhanden ist, wird die -Methode der ProductsBLL Klasse s UpdateWithTransaction aufgerufen. Als Nächstes werden die Daten in GridView ProductsGrid rebound, sodass die neu hinzugefügten Produkte in der Anzeigeoberfläche angezeigt werden. Wird StatusLabel aktualisiert, um eine Bestätigungsmeldung anzuzeigen, und die ReturnToDisplayInterface wird aufgerufen, wobei die Einfügeschnittstelle ausgeblendet und die Anzeigeschnittstelle angezeigt wird.

Wenn keine Produkte eingegeben wurden, bleibt die Einfügeschnittstelle angezeigt, aber die Meldung Keine Produkte wurden hinzugefügt. Bitte geben Sie die Produktnamen und Einzelpreise in die Textfelder ein, die angezeigt werden.

Die Abbildungen 13, 14 und 15 zeigen die Einfüge- und Anzeigeschnittstellen in Aktion. In Abbildung 13 hat der Benutzer einen Preis pro Einheit ohne einen 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 befindet sich auf der vorherigen Seite).

Bei der Eingabe eines Einzelpreises ist ein Produktname erforderlich.

Abbildung 13: Bei der Eingabe eines Einzelpreises ist ein Produktname erforderlich (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Drei neue Gemüse wurden für den Lieferanten Mayumi hinzugefügt

Abbildung 14: Drei neue Gemüsesorten wurden für die Lieferanten Mayumi hinzugefügt (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Die neuen Produkte finden Sie auf der letzten Seite der GridView.

Abbildung 15: Die neuen Produkte finden Sie auf der letzten Seite von GridView (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Hinweis

Die in diesem Tutorial verwendete Batcheinfügungslogik umschließt die Einfügungen innerhalb des Transaktionsbereichs. Um dies zu überprüfen, führen Sie absichtlich einen Fehler auf Datenbankebene ein. Anstatt beispielsweise die neue ProductsRow eigenschaft instance s CategoryID dem ausgewählten Wert in dropDownList Categories zuzuweisen, weisen Sie ihn einem Wert wie i * 5zu. Hier i sehen Sie den Schleifenindexer mit Werten im Bereich von 1 bis 5. Wenn Sie also zwei oder mehr Produkte in der Batcheinfügung hinzufügen, hat das erste Produkt einen gültigen CategoryID Wert (5), aber nachfolgende Produkte verfügen CategoryID über Werte, die nicht mit CategoryID Werten in der Categories Tabelle übereinstimmen. Der Nettoeffekt besteht darin, dass zwar die erste INSERT erfolgreich ist, nachfolgende jedoch mit einer Verletzung der Fremdschlüsseleinschränkung fehlschlagen. Da die Batcheinfügung atomar ist, wird für die erste INSERT Instanz ein Rollback ausgeführt, wodurch die Datenbank in ihren Zustand zurückgesetzt wird, bevor der Batcheinfügungsprozess gestartet wurde.

Zusammenfassung

In diesem und den beiden vorherigen Tutorials haben wir Schnittstellen erstellt, die das Aktualisieren, Löschen und Einfügen von Datenbatches ermöglichen, wobei 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 reduziert und gleichzeitig die Integrität der zugrunde liegenden Daten beibehalten.

In diesem Tutorial wird der Blick auf die Arbeit mit Batchdaten abgeschlossen. In den nächsten Tutorials werden eine Vielzahl erweiterter Datenzugriffsebenen-Szenarien untersucht, darunter die Verwendung gespeicherter Prozeduren in den TableAdapter-Methoden, das Konfigurieren von Einstellungen auf Verbindungs- und Befehlsebene im DAL, das 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 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. Leitende Gutachter für dieses Tutorial waren Hilton Giesenow und S ren Jacob Lauritsen. Möchten Sie meine bevorstehenden MSDN-Artikel lesen? Wenn dies der Fall ist, legen Sie eine Zeile unter abmitchell@4GuysFromRolla.com.