Freigeben über


Durchführen von Batchupdates (C#)

von Scott Mitchell

PDF herunterladen

Erfahren Sie, wie Sie eine vollständig bearbeitbare DataList erstellen, in der sich alle zugehörigen Elemente im Bearbeitungsmodus befinden und deren Werte gespeichert werden können, indem Sie auf der Seite auf eine Schaltfläche "Alle aktualisieren" klicken.

Einleitung

Im vorherigen Lernprogramm haben wir untersucht, wie eine DataList auf Elementebene erstellt wird. Wie bei der standardmäßigen bearbeitbaren GridView enthielt jedes Element in der DataList eine Bearbeitungsschaltfläche, die beim Klicken auf das Element bearbeitbar wäre. Die Bearbeitung auf Elementebene eignet sich zwar gut für Daten, die nur gelegentlich aktualisiert werden, aber bestimmte Anwendungsfallszenarien erfordern, dass der Benutzer viele Datensätze bearbeiten kann. Wenn ein Benutzer Dutzende von Datensätzen bearbeiten muss und gezwungen ist, auf "Bearbeiten" zu klicken, seine Änderungen vorzunehmen und auf "Aktualisieren" zu klicken, kann die Anzahl des Klickens ihre Produktivität beeinträchtigen. In solchen Situationen besteht eine bessere Option darin, eine vollständig bearbeitbare DataList bereitzustellen, bei der sich alle zugehörigen Elemente im Bearbeitungsmodus befinden und deren Werte durch Klicken auf eine Schaltfläche "Alle aktualisieren" auf der Seite bearbeitet werden können (siehe Abbildung 1).

Jedes Element in einer vollständig bearbeitbaren DataList kann geändert werden.

Abbildung 1: Jedes Element in einer vollständig bearbeitbaren DataList kann geändert werden (Klicken, um das Bild in voller Größe anzuzeigen)

In diesem Lernprogramm untersuchen wir, wie Sie Benutzern das Aktualisieren von Lieferantenadresseninformationen mithilfe einer vollständig bearbeitbaren DataList ermöglichen.

Schritt 1: Erstellen der bearbeitbaren Benutzeroberfläche in der DataList s ItemTemplate

Im vorherigen Lernprogramm, in dem wir eine standardmäßige, bearbeitbare DataList auf Elementebene erstellen, haben wir zwei Vorlagen verwendet:

  • ItemTemplate enthält die Benutzeroberfläche im Nur-Lese-Modus (die Label-Websteuerelemente zum Anzeigen von Produktnamen und -preisen).
  • EditItemTemplate enthält die Benutzeroberfläche des Bearbeitungsmodus (die beiden TextBox-Websteuerelemente).

Die DataList-Eigenschaft EditItemIndex regelt, welches DataListItem (sofern vorhanden) mithilfe von EditItemTemplate gerendert wird. Insbesondere wird das DataListItem, dessen ItemIndex mit der DataList-Eigenschaft EditItemIndex übereinstimmt, mithilfe von EditItemTemplate gerendert. Dieses Modell funktioniert gut, wenn jeweils nur ein Element bearbeitet werden kann, aber beim Erstellen einer vollständig bearbeitbaren DataList auseinanderfällt.

Für eine vollständig bearbeitbare DataList möchten wir, dass alleDataListItem Elemente mithilfe der bearbeitbaren Schnittstelle gerendert werden. Die einfachste Möglichkeit, dies zu erreichen, ist das Definieren der bearbeitbaren Schnittstelle in der ItemTemplate. Zum Ändern der Adressinformationen der Lieferanten enthält die bearbeitbare Schnittstelle den Lieferantennamen als Text und dann TextBoxes für die Werte "Adresse", "Ort" und "Land/Region".

Öffnen Sie zunächst die BatchUpdate.aspx Seite, fügen Sie ein DataList-Steuerelement hinzu, und legen Sie dessen ID Eigenschaft auf Suppliers. Wählen Sie im Smarttag "DataList" die Option, ein neues ObjectDataSource-Steuerelement mit dem Namen SuppliersDataSource hinzuzufügen.

Erstellen einer neuen ObjectDataSource namens SuppliersDataSource

Abbildung 2: Erstellen einer neuen ObjectDataSource namens SuppliersDataSource (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Konfigurieren Sie objectDataSource so, dass Daten mithilfe der SuppliersBLL Klassenmethode GetSuppliers() abgerufen werden (siehe Abbildung 3). Wie im vorherigen Lernprogramm arbeiten wir, anstatt die Lieferanteninformationen über ObjectDataSource zu aktualisieren, direkt mit der Geschäftslogikebene zusammen. Legen Sie daher die Dropdownliste auf (Keine) auf der Registerkarte UPDATE fest (siehe Abbildung 4).

Abrufen von Lieferanteninformationen mithilfe der GetSuppliers() -Methode

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

Festlegen der Drop-Down Liste auf (Keine) auf der Registerkarte

Abbildung 4: Festlegen der Drop-Down Liste auf (Keine) auf der Registerkarte "AKTUALISIEREN" (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Nach Abschluss des Assistenten generiert Visual Studio automatisch die DataLists ItemTemplate, um jedes von der Datenquelle zurückgegebene Datenfeld in einem Label-Websteuerelement anzuzeigen. Wir müssen diese Vorlage so ändern, dass sie stattdessen die Bearbeitungsschnittstelle bereitstellt. Dies ItemTemplate kann über den Designer mithilfe der Option "Vorlagen bearbeiten" aus dem Smarttag von DataList oder direkt über die deklarative Syntax angepasst werden.

Nehmen Sie sich einen Moment Zeit, um eine Bearbeitungsschnittstelle zu erstellen, die den Namen des Lieferanten als Text anzeigt, aber TextBoxes für die Adress-, Orts- und Länder-/Regionswerte des Lieferanten enthält. Nachdem Sie diese Änderungen vorgenommen haben, sollte die deklarative Syntax Ihrer Seite wie folgt aussehen:

<asp:DataList ID="Suppliers" runat="server" DataKeyField="SupplierID"
    DataSourceID="SuppliersDataSource">
    <ItemTemplate>
        <h4><asp:Label ID="CompanyNameLabel" runat="server"
            Text='<%# Eval("CompanyName") %>' /></h4>
        <table border="0">
            <tr>
                <td class="SupplierPropertyLabel">Address:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Address" runat="server"
                        Text='<%# Eval("Address") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">City:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="City" runat="server"
                        Text='<%# Eval("City") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">Country:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Country" runat="server"
                        Text='<%# Eval("Country") %>' />
                </td>
            </tr>
        </table>
        <br />
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
</asp:ObjectDataSource>

Hinweis

Wie im vorherigen Lernprogramm muss die DataList in diesem Lernprogramm den Ansichtsstatus aktiviert haben.

In der ItemTemplate verwende ich zwei neue CSS-Klassen, SupplierPropertyLabel und SupplierPropertyValue, die zur Styles.css-Klasse hinzugefügt und so konfiguriert wurden, dass sie die gleichen Stil-Einstellungen wie die CSS-Klassen ProductPropertyLabel und ProductPropertyValue nutzen.

.ProductPropertyLabel, .SupplierPropertyLabel
{
    font-weight: bold;
    text-align: right;
}
.ProductPropertyValue, .SupplierPropertyValue
{
    padding-right: 35px;
}

Nachdem Sie diese Änderungen vorgenommen haben, besuchen Sie diese Seite über einen Browser. Wie in Abbildung 5 dargestellt, zeigt jedes DataList-Element den Lieferantennamen als Text an und verwendet TextBoxes zum Anzeigen der Adresse, des Orts und der Region.

Jeder Lieferant in der DataList kann bearbeitet werden.

Abbildung 5: Jeder Lieferant in der DataList ist bearbeitbar (Zum Anzeigen des Bilds mit voller Größe klicken)

Schritt 2: Hinzufügen einer Schaltfläche "Alle aktualisieren"

Während jeder Lieferant in Abbildung 5 die Felder "Adresse", "Ort" und "Land/Region" in einem TextBox-Element anzeigt, ist derzeit keine Schaltfläche "Aktualisieren" verfügbar. Anstatt eine Schaltfläche "Aktualisieren" pro Element zu haben, gibt es in der Regel eine einzelne Schaltfläche "Aktualisieren Alle" auf der Seite, die, wenn sie angeklickt wird, alle Datensätze in der DataList aktualisiert. In diesem Lernprogramm fügen wir zwei Schaltflächen "Alle aktualisieren" hinzu – eine am oberen Rand der Seite und eine am unteren Rand (obwohl das Klicken auf eine der Schaltflächen denselben Effekt hat).

Fügen Sie zunächst ein Schaltflächenweb-Steuerelement oberhalb der DataList hinzu, und legen Sie dessen ID Eigenschaft auf UpdateAll1. Fügen Sie als Nächstes das zweite Schaltflächen-Websteuerelement unter der DataList hinzu, und setzen Sie es ID auf UpdateAll2. Legen Sie die Text Eigenschaften für die beiden Schaltflächen auf "Alle aktualisieren" fest. Erstellen Sie schließlich Ereignishandler für die Ereignisse beider Schaltflächen Click. Anstatt die Aktualisierungslogik in jedem der Ereignishandler zu duplizieren, lassen Sie uns diese Logik in eine dritte Methode umgestalten, UpdateAllSupplierAddresseswobei die Ereignishandler einfach diese dritte Methode aufrufen.

protected void UpdateAll1_Click(object sender, EventArgs e)
{
    UpdateAllSupplierAddresses();
}
protected void UpdateAll2_Click(object sender, EventArgs e)
{
    UpdateAllSupplierAddresses();
}
private void UpdateAllSupplierAddresses()
{
    // TODO: Write code to update _all_ of the supplier addresses in the DataList
}

Abbildung 6 zeigt die Seite, nachdem die Schaltflächen "Alle aktualisieren" hinzugefügt wurden.

Zwei Schaltflächen zum Aktualisieren aller Schaltflächen wurden der Seite hinzugefügt.

Abbildung 6: Zwei 'Alles aktualisieren' Schaltflächen wurden zur Seite hinzugefügt (Klicken, um das Bild in voller Größe anzuzeigen)

Schritt 3: Aktualisieren aller Adressinformationen der Lieferanten

Bei allen DataList-Elementen, die die Bearbeitungsoberfläche anzeigen, und der Hinzufügung der Schaltfläche "Alle aktualisieren" bleibt nur noch, den Code für die Batchaktualisierung zu schreiben. Insbesondere müssen wir die Elemente der DataList durchlaufen und für jedes die SuppliersBLL-Klasse-UpdateSupplierAddress-Methode aufrufen.

Auf die Sammlung von DataListItem Instanzen, die die DataList erstellen, kann über die DataList-Eigenschaft Itemszugegriffen werden. Mit einem Verweis auf ein DataListItemObjekt können wir das entsprechende SupplierID aus der DataKeys Auflistung abrufen und programmgesteuert auf die TextBox-Websteuerelemente innerhalb des ItemTemplate wie im folgenden Code gezeigt verweisen:

private void UpdateAllSupplierAddresses()
{
    // Create an instance of the SuppliersBLL class
    SuppliersBLL suppliersAPI = new SuppliersBLL();
    // Iterate through the DataList's items
    foreach (DataListItem item in Suppliers.Items)
    {
        // Get the supplierID from the DataKeys collection
        int supplierID = Convert.ToInt32(Suppliers.DataKeys[item.ItemIndex]);
        // Read in the user-entered values
        TextBox address = (TextBox)item.FindControl("Address");
        TextBox city = (TextBox)item.FindControl("City");
        TextBox country = (TextBox)item.FindControl("Country");
        string addressValue = null, cityValue = null, countryValue = null;
        if (address.Text.Trim().Length > 0)
            addressValue = address.Text.Trim();
        if (city.Text.Trim().Length > 0)
              cityValue = city.Text.Trim();
        if (country.Text.Trim().Length > 0)
            countryValue = country.Text.Trim();
        // Call the SuppliersBLL class's UpdateSupplierAddress method
        suppliersAPI.UpdateSupplierAddress
            (supplierID, addressValue, cityValue, countryValue);
    }
}

Wenn der Benutzer auf eine der Schaltflächen "Alle aktualisieren" klickt, durchläuft die UpdateAllSupplierAddresses-Methode jede DataListItem in der Suppliers-DataList und ruft die SuppliersBLL-Methode der UpdateSupplierAddress-Klasse auf, wobei die entsprechenden Werte übergeben werden. Ein nicht eingegebener Wert für Adress-, Orts- oder Länder-/Regionsdurchläufe ist ein Wert von Nothing ( UpdateSupplierAddress anstelle einer leeren Zeichenfolge), der zu einer Datenbank NULL für die zugrunde liegenden Datensatzfelder führt.

Hinweis

Als Erweiterung möchten Sie der Seite möglicherweise ein Statusbezeichnung-Websteuerelement hinzufügen, das nach der Batchaktualisierung eine Bestätigungsmeldung bereitstellt.

Aktualisieren nur der Adressen, die geändert wurden

Der für dieses Lernprogramm verwendete Batchaktualisierungsalgorithmus ruft die UpdateSupplierAddress Methode für jeden Lieferanten in der DataList auf, unabhängig davon, ob ihre Adressinformationen geändert wurden. Während solche Blindupdates in der Regel kein Leistungsproblem sind, können sie zu überflüssigen Datensätzen führen, wenn Sie Änderungen an der Datenbanktabelle überwachen. Wenn Sie beispielsweise Trigger verwenden, um alle UPDATE-Einträge in der Suppliers-Tabelle in einer Audit-Tabelle aufzuzeichnen, wird jedes Mal, wenn ein Benutzer auf die Schaltfläche "Alle aktualisieren" klickt, für jeden Lieferanten im System ein neuer Audit-Datensatz erstellt, unabhängig davon, ob der Benutzer Änderungen vorgenommen hat.

Die ADO.NET DataTable- und DataAdapter-Klassen sind so konzipiert, dass Batchaktualisierungen unterstützt werden, bei denen nur geänderte, gelöschte und neue Datensätze zu einer beliebigen Datenbankkommunikation führen. Jede Zeile in der DataTable weist eine RowState Eigenschaft auf, die angibt, ob die Zeile der DataTable hinzugefügt, daraus gelöscht, geändert oder unverändert bleibt. Wenn eine DataTable anfangs aufgefüllt wird, werden alle Zeilen unverändert markiert. Wenn Sie den Wert einer der Zeilenspalten ändern, wird die Zeile als geändert markiert.

In der SuppliersBLL Klasse aktualisieren wir die angegebenen Adressinformationen des Lieferanten, indem wir zuerst den Datensatz des einzelnen Lieferanten in einen SuppliersDataTable einlesen und dann die Werte der Spalten Address, City und Country mithilfe des folgenden Codes festlegen.

public bool UpdateSupplierAddress
    (int supplierID, string address, string city, string country)
{
    Northwind.SuppliersDataTable suppliers =
        Adapter.GetSupplierBySupplierID(supplierID);
    if (suppliers.Count == 0)
        // no matching record found, return false
        return false;
    else
    {
        Northwind.SuppliersRow supplier = suppliers[0];
        if (address == null)
            supplier.SetAddressNull();
        else
            supplier.Address = address;
        if (city == null)
            supplier.SetCityNull();
        else
            supplier.City = city;
        if (country == null)
            supplier.SetCountryNull();
        else
            supplier.Country = country;
        // Update the supplier Address-related information
        int rowsAffected = Adapter.Update(supplier);
        // Return true if precisely one row was updated,
        // otherwise false
        return rowsAffected == 1;
    }
}

Dieser Code weist naiv die übergebenen Adress-, Orts- und Länder-/Regionswerte den Platzhaltern SuppliersRow im SuppliersDataTable zu, unabhängig davon, ob sich die Werte geändert haben. Diese Änderungen bewirken, dass die Eigenschaft SuppliersRow s RowState als geändert markiert wird. Wenn die Data Access Layer-Methode Update aufgerufen wird, sieht sie, dass die SupplierRow Änderung erfolgt ist und sendet daher einen UPDATE Befehl an die Datenbank.

Stellen Sie sich jedoch vor, dass wir dieser Methode Code hinzugefügt haben, um nur die übergebenen Adress-, Orts- und Länder-/Regionswerte zuzuweisen, wenn sie sich von den SuppliersRow vorhandenen Werten unterscheiden. Wenn die Adresse, die Stadt und die Region mit den vorhandenen Daten identisch sind, werden keine Änderungen vorgenommen, und die SupplierRow Daten RowState werden unverändert markiert. Das Nettoergebnis ist, dass beim Aufrufen der DAL-Methode Update kein Datenbankaufruf erfolgt, da die SuppliersRow Methode nicht geändert wurde.

Um diese Änderung umzusetzen, ersetzen Sie die Anweisungen im Code, die unüberlegt die übergebenen Adress-, Orts- und Länder-/Regionswerte zuweisen, mit dem folgenden Code:

// Only assign the values to the SupplierRow's column values if they differ
if (address == null && !supplier.IsAddressNull())
    supplier.SetAddressNull();
else if ((address != null && supplier.IsAddressNull()) ||
         (!supplier.IsAddressNull() &&
         string.Compare(supplier.Address, address) != 0))
    supplier.Address = address;
if (city == null && !supplier.IsCityNull())
    supplier.SetCityNull();
else if ((city != null && supplier.IsCityNull()) ||
         (!supplier.IsCityNull() && string.Compare(supplier.City, city) != 0))
    supplier.City = city;
if (country == null && !supplier.IsCountryNull())
    supplier.SetCountryNull();
else if ((country != null && supplier.IsCountryNull()) ||
         (!supplier.IsCountryNull() &&
         string.Compare(supplier.Country, country) != 0))
    supplier.Country = country;

Mit diesem hinzugefügten Code sendet die DAL-Methode Update eine UPDATE Anweisung an die Datenbank nur für die Datensätze, bei denen sich die adressbezogenen Werte geändert haben.

Alternativ können wir nachverfolgen, ob es Unterschiede zwischen den übergebenen Adressfeldern und den Datenbankdaten gibt. Wenn keines vorhanden ist, umgehen Sie einfach den Aufruf der DAL s-Methode Update . Dieser Ansatz funktioniert gut, wenn Sie die Direkte DB-Methode verwenden, da der Direkten DB-Methode keine SuppliersRow-Instanz übergeben wird, deren RowState überprüft werden kann, um festzustellen, ob ein Datenbankaufruf tatsächlich benötigt wird.

Hinweis

Jedes Mal, wenn die UpdateSupplierAddress Methode aufgerufen wird, wird ein Aufruf der Datenbank ausgeführt, um Informationen zum aktualisierten Datensatz abzurufen. Wenn dann Änderungen an den Daten vorliegen, wird ein weiterer Aufruf der Datenbank vorgenommen, um die Tabellenzeile zu aktualisieren. Dieser Workflow kann optimiert werden, indem eine UpdateSupplierAddress Methodenüberladung erstellt wird, die eine EmployeesDataTable Instanz akzeptiert, die alle Änderungen von der BatchUpdate.aspx Seite enthält. Anschließend könnte die Datenbank einen Aufruf ausführen, um alle Datensätze aus der Suppliers Tabelle abzurufen. Die beiden Resultsets können dann aufgezählt werden, und nur die Datensätze, in denen Änderungen vorgenommen wurden, konnten aktualisiert werden.

Zusammenfassung

In diesem Lernprogramm haben wir erfahren, wie Sie eine vollständig bearbeitbare DataList erstellen, sodass ein Benutzer die Adressinformationen für mehrere Lieferanten schnell ändern kann. Wir begannen damit, die Bearbeitungsschnittstelle mit einem TextBox-Websteuerelement für die Adressen, Stadt und Länder/Region des Lieferanten im DataListItemTemplate zu definieren. Als Nächstes haben wir oben und unterhalb der DataList "Alle aktualisieren"-Schaltflächen hinzugefügt. Nachdem ein Benutzer seine Änderungen vorgenommen und auf eine der Schaltflächen "Alle aktualisieren" geklickt hat, werden die DataListItem Elemente aufgezählt, und ein Aufruf der Methode der SuppliersBLL Klasse UpdateSupplierAddress erfolgt.

Glückliche Programmierung!

Zum Autor

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

Besonderer Dank an

Diese Lernprogrammreihe wurde von vielen hilfreichen Prüfern überprüft. Leitende Prüfer für dieses Lernprogramm waren Zack Jones und Ken Pespisa. Möchten Sie meine bevorstehenden MSDN-Artikel überprüfen? Wenn ja, schicken Sie mir eine Nachricht an mitchell@4GuysFromRolla.com.