Wykonywanie aktualizacji wsadowych (C#)
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).
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
.
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).
Rysunek 3. Pobieranie informacji o dostawcy przy użyciu GetSuppliers()
metody (kliknij, aby wyświetlić obraz pełnowymiarowy)
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.
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 , UpdateAllSupplierAddresses
dzię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.
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 DataListItem
moż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 Address
wartości kolumn , City
i 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 .