Udostępnij za pośrednictwem


Wykonywanie aktualizacji wsadowych (C#)

Autor: Scott Mitchell

Pobierz plik PDF

Dowiedz się, jak utworzyć w pełni edytowalną listę danych, w której wszystkie jego elementy są w trybie edycji i których wartości można zapisać, klikając przycisk "Aktualizuj wszystko" na stronie.

Wprowadzenie

W poprzednim samouczku sprawdziliśmy, jak utworzyć listę danych na poziomie elementu. Podobnie jak w przypadku standardowego edytowalnego elementu GridView, każdy element na liście danych zawiera przycisk Edytuj, który po kliknięciu spowoduje, że element będzie edytowalny. Chociaż edytowanie na poziomie elementu działa dobrze w przypadku danych, które są aktualizowane tylko od czasu do czasu, niektóre scenariusze przypadków użycia wymagają od użytkownika edytowania wielu rekordów. Jeśli użytkownik musi edytować dziesiątki rekordów i musi kliknąć przycisk Edytuj, wprowadzić zmiany i kliknąć przycisk Aktualizuj dla każdego z nich, ilość kliknięć może utrudnić jej produktywność. W takich sytuacjach lepszym rozwiązaniem jest udostępnienie w pełni edytowalnej listy danych, w której wszystkie jego elementy są w trybie edycji i których wartości można edytować, klikając przycisk Aktualizuj wszystko na stronie (patrz Rysunek 1).

Każdy element w w pełni edytowalnej listy danych można modyfikować

Rysunek 1. Każdy element w w pełni edytowalnej listy danych można zmodyfikować (kliknij, aby wyświetlić obraz pełnowymiarowy)

W tym samouczku sprawdzimy, jak umożliwić użytkownikom aktualizowanie informacji o adresach dostawców przy użyciu w pełni edytowalnej listy danych.

Krok 1. Tworzenie edytowalnego interfejsu użytkownika w elemencie ItemTemplate elementu DataList

W poprzednim samouczku, w którym utworzyliśmy standardową, edytowalną listę danych na poziomie elementu, użyliśmy dwóch szablonów:

  • ItemTemplate zawierał interfejs użytkownika tylko do odczytu (kontrolki Etykieta sieci Web do wyświetlania nazwy i ceny poszczególnych produktów).
  • EditItemTemplate zawierał interfejs użytkownika trybu edycji (dwa kontrolki sieci Web TextBox).

Właściwość DataList EditItemIndex określa, co DataListItem (jeśli istnieje) jest renderowane przy użyciu elementu EditItemTemplate. W szczególności wartość, DataListItem której ItemIndex wartość jest zgodna z właściwością DataList, EditItemIndex jest renderowana przy użyciu elementu EditItemTemplate. Ten model działa dobrze, gdy tylko jeden element można edytować naraz, ale rozpada się podczas tworzenia w pełni edytowalnej listy danych.

W przypadku w pełni edytowalnej listy danych chcemy, aby wszystkieDataListItem elementy s renderowane przy użyciu interfejsu edytowalnego. Najprostszym sposobem na to jest zdefiniowanie edytowalnego interfejsu w pliku ItemTemplate. Aby zmodyfikować informacje o adresach dostawców, edytowalny interfejs zawiera nazwę dostawcy jako tekst, a następnie Pola tekstowe dla wartości adresu, miasta i kraju/regionu.

Zacznij od otwarcia BatchUpdate.aspx strony, dodaj kontrolkę DataList i ustaw jej ID właściwość na Suppliers. Z tagu inteligentnego DataList wybierz opcję dodania nowej kontrolki ObjectDataSource o nazwie SuppliersDataSource.

Tworzenie nowego obiektuDataSource o nazwie SuppliersDataSource

Rysunek 2. Utwórz nową nazwę ObjectDataSource o nazwie SuppliersDataSource (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Skonfiguruj obiekt ObjectDataSource, aby pobrać dane przy użyciu SuppliersBLL metody klasy s GetSuppliers() (zobacz Rysunek 3). Podobnie jak w przypadku poprzedniego samouczka, zamiast aktualizować informacje o dostawcy za pośrednictwem obiektu ObjectDataSource, będziemy pracować bezpośrednio z warstwą logiki biznesowej. W związku z tym ustaw listę rozwijaną na (Brak) na karcie UPDATE (zobacz Rysunek 4).

Pobieranie informacji o dostawcy przy użyciu metody GetSuppliers()

Rysunek 3. Pobieranie informacji o dostawcy przy użyciu GetSuppliers() metody (kliknij, aby wyświetlić obraz pełnowymiarowy)

Ustaw listę Drop-Down na wartość (Brak) na karcie UPDATE

Rysunek 4. Ustawianie listy Drop-Down na wartość (Brak) na karcie UPDATE (Kliknij, aby wyświetlić obraz pełnowymiarowy)

Po ukończeniu pracy kreatora program Visual Studio automatycznie generuje listę ItemTemplate danych, aby wyświetlić każde pole danych zwrócone przez źródło danych w kontrolce Sieci Web etykiet. Musimy zmodyfikować ten szablon, aby zamiast tego udostępniał interfejs do edycji. Można ItemTemplate je dostosować za pomocą Projektant za pomocą opcji Edytuj szablony z tagu inteligentnego DataList lub bezpośrednio za pomocą składni deklaratywnej.

Poświęć chwilę na utworzenie interfejsu edycji, który wyświetla nazwę dostawcy jako tekst, ale zawiera pola TextBoxes dla wartości adresu dostawcy, miasta i kraju/regionu. Po wprowadzeniu tych zmian składnia deklaratywna strony powinna wyglądać podobnie do następującej:

<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>

Uwaga

Podobnie jak w przypadku poprzedniego samouczka, lista DataList w tym samouczku musi mieć włączony stan widoku.

W programie ItemTemplate używam dwóch nowych klas SupplierPropertyLabel CSS i SupplierPropertyValue, które zostały dodane do Styles.css klasy i skonfigurowane do używania tych samych ustawień stylu co ProductPropertyLabel klasy i ProductPropertyValue CSS.

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

Po wprowadzeniu tych zmian odwiedź tę stronę za pośrednictwem przeglądarki. Jak pokazano na rysunku 5, każdy element DataList wyświetla nazwę dostawcy jako tekst i używa pola TextBoxes do wyświetlania adresu, miasta i kraju/regionu.

Każdy dostawca na liście danych jest edytowalny

Rysunek 5. Każdy dostawca na liście danych jest edytowalny (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 2. Dodawanie przycisku Aktualizuj wszystko

Chociaż każdy dostawca na rysunku 5 ma swoje pola adresowe, miasto i kraj/region wyświetlane w polu TekstBox, obecnie nie ma dostępnego przycisku Aktualizuj. Zamiast przycisku Aktualizuj dla każdego elementu, w pełni edytowalne listy danych na stronie zazwyczaj znajduje się jeden przycisk Aktualizuj wszystko, który po kliknięciu aktualizuje wszystkie rekordy na liście Danych. W tym samouczku dodajmy dwa przyciski Aktualizuj wszystkie — jeden w górnej części strony i jeden u dołu (chociaż kliknięcie jednego przycisku będzie miało taki sam efekt).

Zacznij od dodania kontrolki Sieć Web przycisku nad listą DataList i ustaw jej ID właściwość na UpdateAll1. Następnie dodaj drugą kontrolkę Sieć Web przycisku pod listą DataList, ustawiając jej ID wartość na UpdateAll2. Text Ustaw właściwości dla dwóch przycisków na Wartość Aktualizuj wszystko. Na koniec utwórz programy obsługi zdarzeń dla obu zdarzeń Przycisków Click . Zamiast duplikować logikę aktualizacji w każdym z programów obsługi zdarzeń, refaktoryzujmy tę logikę do trzeciej metody , UpdateAllSupplierAddressesdzięki czemu programy obsługi zdarzeń po prostu wywołają tę trzecią metodę.

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
}

Rysunek 6 przedstawia stronę po dodaniu przycisków Aktualizuj wszystkie.

Do strony zostały dodane dwa przyciski Aktualizuj wszystkie

Rysunek 6. Dodano dwa przyciski Aktualizuj wszystkie do strony (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 3. Aktualizowanie wszystkich informacji o adresach dostawców

Po wyświetleniu interfejsu edycji i dodaniu wszystkich przycisków Aktualizuj wszystkie pozostałe elementy zapisuje kod do wykonania aktualizacji wsadowej. W szczególności musimy pętli przez elementy DataList i wywołać metodę SuppliersBLL klasy s UpdateSupplierAddress dla każdego z nich.

Do kolekcji DataListItem wystąpień, do których można uzyskać dostęp za pośrednictwem właściwości DataListItems. Przy odwołaniu do elementu DataListItemmożemy pobrać odpowiedni SupplierID element z DataKeys kolekcji i programowo odwołać się do kontrolek sieci Web TextBox w ItemTemplate programie , jak pokazano w poniższym kodzie:

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);
    }
}

Gdy użytkownik kliknie jeden z przycisków Aktualizuj wszystkie, UpdateAllSupplierAddresses metoda wykonuje iterację po każdej DataListItem z nich w elemecie Suppliers DataList i wywołuje SuppliersBLL metodę klasy s UpdateSupplierAddress , przekazując odpowiednie wartości. Niewprowadzona wartość dla adresu, miasta lub kraju/regionu jest wartością Nothing do UpdateSupplierAddress (zamiast pustego ciągu), co powoduje utworzenie bazy danych NULL dla pól rekordu bazowego.

Uwaga

W ramach ulepszenia możesz dodać kontrolkę sieci Web etykieta stanu do strony, która dostarcza komunikat potwierdzający po wykonaniu aktualizacji wsadowej.

Aktualizowanie tylko tych adresów, które zostały zmodyfikowane

Algorytm aktualizacji wsadowej używany w tym samouczku wywołuje metodę UpdateSupplierAddress dla każdego dostawcy w liście DataList, niezależnie od tego, czy informacje o adresach zostały zmienione. Chociaż takie niewidome aktualizacje nie są zwykle problemem z wydajnością, mogą prowadzić do nadmiarowych rekordów, jeśli przeprowadzasz inspekcję zmian w tabeli bazy danych. Jeśli na przykład używasz wyzwalaczy do rejestrowania wszystkich UPDATE elementów w Suppliers tabeli do tabeli inspekcji, za każdym razem, gdy użytkownik kliknie przycisk Aktualizuj wszystko, zostanie utworzony nowy rekord inspekcji dla każdego dostawcy w systemie, niezależnie od tego, czy użytkownik dokonał jakichkolwiek zmian.

Klasy ADO.NET DataTable i DataAdapter są przeznaczone do obsługi aktualizacji wsadowych, w których tylko zmodyfikowane, usunięte i nowe rekordy będą skutkować komunikacją z dowolną bazą danych. Każdy wiersz w tabeli DataTable ma właściwość wskazującąRowState, czy wiersz został dodany do tabeli DataTable, usunięty z niego, zmodyfikowany lub pozostaje niezmieniony. Gdy tabela danych jest początkowo wypełniana, wszystkie wiersze są oznaczone bez zmian. Zmiana wartości dowolnej kolumny wiersza oznacza wiersz zgodnie z modyfikacją.

SuppliersBLL W klasie aktualizujemy informacje o adresach określonego dostawcy, najpierw odczytując w rekordzie pojedynczego dostawcySuppliersDataTable, a następnie ustawiamy Addresswartości kolumn , Cityi Country przy użyciu następującego kodu:

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;
    }
}

Ten kod naiwnie przypisuje przekazane wartości adresu, miasta i kraju/regionu do SuppliersRow wartości w SuppliersDataTable niezależnie od tego, czy wartości uległy zmianie. Te modyfikacje powodują SuppliersRow oznaczenie właściwości s RowState jako zmodyfikowanej. Gdy wywoływana jest metoda warstwy Update dostępu do danych, zobaczy, że SupplierRow element został zmodyfikowany i dlatego wysyła UPDATE polecenie do bazy danych.

Załóżmy jednak, że dodaliśmy kod do tej metody w celu przypisania tylko przekazanych wartości adresu, miasta i kraju/regionu, jeśli różnią się od SuppliersRow istniejących wartości. W przypadku, gdy adres, miasto i kraj/region są takie same jak istniejące dane, nie zostaną wprowadzone żadne zmiany, a SupplierRow znaki s RowState zostaną oznaczone jako niezmienione. Wynikiem netto jest to, że po wywołaniu metody DAL Update nie zostanie wykonane żadne wywołanie bazy danych, ponieważ SuppliersRow nie został zmodyfikowany.

Aby wprowadzić tę zmianę, zastąp instrukcje, które ślepo przypisują przekazany adres, miasto i wartości kraju/regionu następującym kodem:

// 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;

Dzięki temu dodanemu kodzie metoda DAL Update wysyła instrukcję UPDATE do bazy danych tylko dla tych rekordów, których wartości związane z adresami uległy zmianie.

Alternatywnie można śledzić, czy istnieją jakiekolwiek różnice między przekazanymi polami adresów a danymi bazy danych, a jeśli nie ma ich, po prostu pominąć wywołanie metody DAL Update . Takie podejście działa dobrze, jeśli używasz metody bezpośredniej bazy danych, ponieważ metoda bezpośrednia bazy danych nie jest przekazywana SuppliersRow do wystąpienia, którego RowState można sprawdzić, czy wywołanie bazy danych jest rzeczywiście potrzebne.

Uwaga

Za każdym razem, gdy UpdateSupplierAddress metoda jest wywoływana, do bazy danych jest wykonywane wywołanie w celu pobrania informacji o zaktualizowanym rekordzie. Następnie, jeśli istnieją jakiekolwiek zmiany w danych, następuje kolejne wywołanie bazy danych w celu zaktualizowania wiersza tabeli. Ten przepływ pracy można zoptymalizować, tworząc UpdateSupplierAddress przeciążenie metody, które akceptuje EmployeesDataTable wystąpienie, które zawiera wszystkie zmiany ze BatchUpdate.aspx strony. Następnie może wykonać jedno wywołanie bazy danych, aby pobrać wszystkie rekordy z Suppliers tabeli. Te dwa zestawy wyników można następnie wyliczyć i tylko te rekordy, w których wystąpiły zmiany.

Podsumowanie

W tym samouczku pokazano, jak utworzyć w pełni edytowalną listę danych, umożliwiając użytkownikowi szybkie modyfikowanie informacji o adresie dla wielu dostawców. Zaczęliśmy od zdefiniowania interfejsu edycji kontrolki internetowej TextBox dla adresu dostawcy, miasta i kraju/regionu wartości w elemecie DataList s ItemTemplate. Następnie dodaliśmy przyciski Aktualizuj wszystkie powyżej i poniżej listy danych. Po wprowadzeniu zmian przez użytkownika i kliknięciu jednego z przycisków Aktualizuj wszystkie zostaną wyliczone DataListItem , a wywołanie SuppliersBLL metody klasy s UpdateSupplierAddress zostanie wykonane.

Szczęśliwe programowanie!

Informacje o autorze

Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można do niego dotrzeć pod adresem mitchell@4GuysFromRolla.com. Lub za pośrednictwem swojego bloga, który można znaleźć na stronie http://ScottOnWriting.NET.

Specjalne podziękowania

Ta seria samouczków została przejrzyona przez wielu przydatnych recenzentów. Głównymi recenzentami tego samouczka byli Zack Jones i Ken Pespisa. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi wiersz pod adresemmitchell@4GuysFromRolla.com .