Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Autor : Scott Mitchell
Dowiedz się, jak zaktualizować wiele rekordów bazy danych w ramach jednej operacji. W warstwie interfejsu użytkownika tworzymy obiekt GridView, w którym każdy wiersz można edytować. W warstwie dostępu do danych opakowujemy wiele operacji aktualizacji w ramach transakcji, aby upewnić się, że wszystkie aktualizacje zakończą się powodzeniem lub zostaną wycofane.
Wprowadzenie
W poprzednim samouczku pokazano, jak rozszerzyć warstwę dostępu do danych w celu dodania obsługi transakcji bazy danych. Transakcje bazy danych gwarantują, że seria instrukcji modyfikacji danych będzie traktowana jako jedna operacja atomowa, co gwarantuje, że wszystkie modyfikacje nie powiedzie się lub wszystkie zostaną wykonane pomyślnie. Dzięki tej funkcji DAL niskiego poziomu możemy teraz skupić się na tworzeniu interfejsów do modyfikacji danych wsadowych.
W tym samouczku utworzymy obiekt GridView, w którym można edytować każdy wiersz (zobacz Rysunek 1). Ponieważ każdy wiersz jest renderowany w interfejsie edycji, nie ma potrzeby tworzenia kolumn przycisków Edytuj, Aktualizuj i Anuluj. Zamiast tego na stronie znajdują się dwa przyciski Aktualizuj produkty, które po kliknięciu wyliczają wiersze GridView i aktualizują bazę danych.
Rysunek 1. Każdy wiersz w widoku GridView jest edytowalny (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Zacznijmy!
Uwaga / Notatka
W samouczku Wykonywanie aktualizacji wsadowych utworzyliśmy interfejs edycji wsadowej przy wykorzystaniu kontrolki DataList. Ten samouczek różni się od poprzedniego tym, że używa kontrolki GridView, a aktualizacja wsadowa jest wykonywana w zakresie transakcji. Po ukończeniu tego samouczka zachęcam do powrotu do wcześniejszego samouczka i zaktualizowania go do korzystania z funkcji związanych z transakcjami bazy danych dodanych w poprzednim samouczku.
Analiza kroków umożliwiających edytowanie wszystkich wierszy w GridView
Zgodnie z opisem w samouczku Omówienie wstawiania, aktualizowania i usuwania danych funkcja GridView oferuje wbudowaną obsługę edytowania danych bazowych na podstawie wiersza. Wewnętrznie kontrolka GridView zauważa, jaki wiersz można edytować za pomocą jego EditIndex właściwości. Ponieważ element GridView jest powiązany ze źródłem danych, sprawdza każdy wiersz, aby sprawdzić, czy indeks wiersza jest równy wartości EditIndex. Jeśli tak, pola tego wiersza są renderowane przy użyciu interfejsów edycji. W przypadku obiektu BoundField interfejs edycji to TextBox, którego właściwość Text ma przypisaną wartość pola danych określonego przez właściwość DataField BoundField. W przypadku obiektów TemplateFields EditItemTemplate wykorzystuje się zamiast ItemTemplate.
Pamiętaj, że edytowanie przepływu pracy rozpoczyna się, gdy użytkownik kliknie przycisk Edytuj wiersz. Powoduje to powrót, ustawia właściwość GridView EditIndex na indeks klikniętego wiersza i ponownie tworzy powiązanie danych z siatką. Po kliknięciu przycisku Anuluj wiersza, podczas ogłaszania zwrotnego, zostanie ustawiona wartość EditIndex przed ponownym powiązaniem danych z siatką. Ponieważ wiersze kontrolki GridView zaczynają indeksować od zera, ustawienie EditIndex-1 ma wpływ na wyświetlanie kontrolki GridView w trybie tylko do odczytu.
Właściwość EditIndex działa dobrze dla edytowania poszczególnych wierszy, ale nie jest przeznaczona do edycji wsadowej. Aby edytować cały element GridView, musimy mieć każdy wiersz renderowany przy użyciu interfejsu edycji. Najprostszym sposobem osiągnięcia tego celu jest utworzenie miejsca, w którym każde pole edytowalne jest implementowane jako pole szablonu z interfejsem edycji zdefiniowanym w pliku ItemTemplate.
W kolejnych kilku krokach utworzymy całkowicie edytowalny element GridView. W kroku 1 zaczniemy od utworzenia kontrolki GridView i jej obiektu ObjectDataSource oraz przekonwertowania pól BoundFields i CheckBoxField na pola szablonów. W etapach 2 i 3 przeniesiemy interfejsy edycji z pól szablonów EditItemTemplate do ich odpowiedników ItemTemplate.
Krok 1. Wyświetlanie informacji o produkcie
Zanim zaczniemy martwić się o utworzenie kontrolki GridView, w której można edytować wiersze, zacznijmy od wyświetlenia informacji o produkcie.
BatchUpdate.aspx Otwórz stronę w folderze BatchData i przeciągnij kontrolkę GridView z przybornika do projektanta. Ustaw właściwość ID kontrolki GridView na wartość ProductsGrid, a następnie z jej inteligentnego tagu wybierz opcję powiązania z nowym obiektem ObjectDataSource o nazwie ProductsDataSource. Skonfiguruj obiekt ObjectDataSource, aby pobrać dane z ProductsBLL metody klasy s GetProducts .
Rysunek 2. Konfigurowanie obiektu ObjectDataSource do używania ProductsBLL klasy (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Rysunek 3. Pobieranie danych produktu przy użyciu GetProducts metody (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Podobnie jak w przypadku kontrolki GridView, funkcje modyfikacji obiektu ObjectDataSource są przeznaczone do pracy w poszczególnych wierszach. Aby zaktualizować zestaw rekordów, musimy napisać trochę kodu w klasie code-behind ASP.NET, która grupuje dane i przekazuje je do warstwy BLL. W związku z tym ustaw listy rozwijane w zakładkach UPDATE, INSERT i DELETE kontrolki ObjectDataSource na wartość (Brak). Kliknij przycisk Zakończ, aby ukończyć pracę kreatora.
Rysunek 4. Ustawianie list Drop-Down na kartach UPDATE, INSERT i DELETE na wartość (Brak) (Kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Po ukończeniu kreatora Konfiguracji źródła danych znacznik deklaratywny ObjectDataSource powinien wyglądać następująco:
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
Ukończenie pracy kreatora konfigurowania źródła danych powoduje również, że program Visual Studio tworzy pola BoundFields i CheckBoxField dla pól danych produktu w elemencie GridView. W tym samouczku pozwólmy użytkownikowi wyświetlać i edytować tylko nazwę produktu, kategorię, cenę oraz status wycofania. Usuń wszystkie pola poza ProductName, CategoryName, UnitPrice i Discontinued oraz zmień nazwy właściwości HeaderText pierwszych trzech pól na odpowiednio: Produkt, Kategoria i Cena. Na koniec zaznacz pola wyboru Włącz stronicowanie i Włącz sortowanie w tagu inteligentnym GridView.
W tym momencie kontrolka GridView ma trzy pola powiązane (ProductName, CategoryName, i UnitPrice) oraz pole wyboru (Discontinued). Musimy przekonwertować te cztery pola na pola szablonów, a następnie przenieść interfejs edycji z pola szablonu EditItemTemplate do elementu ItemTemplate.
Uwaga / Notatka
Zapoznaliśmy się z tworzeniem i dostosowywaniem pól szablonów w samouczku Dostosowywanie interfejsu modyfikacji danych. Przejdziemy przez kroki konwertowania pól BoundFields i CheckBoxField na pola TemplateFields oraz definiowania ich interfejsów edycji w ich ItemTemplate, ale jeśli utkniesz lub potrzebujesz przypomnienia, nie wahaj się odwołać się do tego wcześniejszego samouczka.
W tagu inteligentnym GridView kliknij link Edytuj kolumny, aby otworzyć okno dialogowe Pola. Następnie zaznacz każde pole i kliknij łącze Konwertuj to pole na pole szablonu.
Rysunek 5. Konwertowanie istniejących pól granic i pola CheckBoxField na pole szablonu
Teraz, gdy każde pole jest TemplateField, możemy teraz przenieść interfejs edycji z EditItemTemplate do ItemTemplate.
Krok 2: TworzenieProductName,UnitPrice, a takżeDiscontinuededytowanie interfejsów
Tworzenie interfejsów edycji ProductName, UnitPrice i Discontinued jest tematem tego kroku i jest dość proste, ponieważ każdy interfejs jest już zdefiniowany w obszarze TemplateField EditItemTemplate. Tworzenie interfejsu CategoryName edycji jest nieco bardziej skomplikowane, ponieważ musimy utworzyć listę rozwijaną odpowiednich kategorii. Ten CategoryName interfejs edycji jest rozwiązywany w kroku 3.
Zacznijmy od pola ProductName TemplateField. Kliknij łącze Edytuj szablony w inteligentnym tagu GridView i przejdź do pola szablonu ProductName TemplateField EditItemTemplate. Wybierz pole tekstowe, skopiuj je do schowka, a następnie wklej je do pola ProductName TemplateField ItemTemplate. Zmień właściwość TextBox ID na ProductName.
Następnie dodaj element RequiredFieldValidator do ItemTemplate elementu , aby upewnić się, że użytkownik podaje wartość dla każdej nazwy produktu. Ustaw właściwość ControlToValidate na ProductName, właściwość ErrorMessage na Musisz podać nazwę produktu.
Text i właściwość na *. Po dodaniu tych dodatków do ItemTemplate, ekran powinien wyglądać podobnie do rysunku 6.
Rysunek 6. Pole ProductName szablonu zawiera teraz pole tekstowe i element RequiredFieldValidator (kliknij, aby wyświetlić obraz pełnowymiarowy)
Dla interfejsu edycji UnitPrice zacznij od skopiowania kontrolki TextBox z EditItemTemplate do ItemTemplate. Następnie umieść wartość $ przed polem TextBox i ustaw jego właściwość ID na UnitPrice oraz właściwość Columns na 8.
Dodaj również element CompareValidator do UnitPrice s ItemTemplate , aby upewnić się, że wartość wprowadzona przez użytkownika jest prawidłową wartością waluty większą lub równą 0,00 USD. Ustaw właściwość modułu sprawdzania ControlToValidate na UnitPrice, jej właściwość ErrorMessage na Musisz wprowadzić prawidłową wartość waluty. Pomiń wszelkie symbole waluty. Ustaw jej Text właściwość na *, jej Type właściwość na Currency, jej Operator właściwość na GreaterThanEqual, i jej ValueToCompare właściwość na 0.
Rysunek 7. Dodawanie modułu CompareValidator w celu upewnienia się, że wprowadzona cena jest wartością waluty innej niż ujemna (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
W polu Discontinued TemplateField można zastosować CheckBox już wcześniej zdefiniowany w ItemTemplate. Po prostu ustaw jego ID na Wycofane i jego właściwość Enabled na true.
Krok 3. Tworzenie interfejsu edycjiCategoryName
Interfejs edycji w polach CategoryName TemplateFields EditItemTemplate zawiera pole tekstowe wyświetlające wartość pola danych CategoryName. Musimy zastąpić to listą rozwijaną, która zawiera listę możliwych kategorii.
Uwaga / Notatka
Samouczek Dostosowywanie interfejsu modyfikacji danych zawiera bardziej szczegółową i kompletną dyskusję na temat dostosowywania szablonu w celu uwzględnienia listy rozwijanej zamiast TextBox. Kroki opisane w tym miejscu są kompletne, ale są one prezentowane w sposób zwięzły. Aby uzyskać bardziej szczegółowe informacje na temat tworzenia i konfigurowania kategorii DropDownList, zapoznaj się z samouczkiem "Dostosowywanie interfejsu modyfikacji danych".
Przeciągnij listę DropDownList z przybornika na CategoryName TemplateField ItemTemplate, ustawiając jego właściwość ID na Categories. Na tym etapie zwykle definiujemy źródło danych DropDownLists za pomocą tagu inteligentnego, tworząc nowy obiekt ObjectDataSource. Spowoduje to jednak dodanie ObjectDataSource wewnątrz ItemTemplate, w wyniku czego zostanie utworzona instancja ObjectDataSource dla każdego wiersza w GridView. Zamiast tego utwórzmy obiekt ObjectDataSource poza polami TemplateFields kontrolki GridView. Zakończ edytowanie szablonu i przeciągnij obiekt ObjectDataSource z Przybornika do Projektanta pod elementem ObjectDataSource ProductsDataSource. Nadaj nowemu ObjectDataSource CategoriesDataSource nazwę i skonfiguruj go, aby korzystał z klasy CategoriesBLL i metody GetCategories.
Rysunek 8. Konfigurowanie obiektu ObjectDataSource do używania CategoriesBLL klasy (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Rysunek 9. Pobieranie danych kategorii przy użyciu GetCategories metody (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Ponieważ to ObjectDataSource jest używane wyłącznie do pobierania danych, ustaw listy rozwijane w kartach UPDATE i DELETE na wartość (Brak). Kliknij przycisk Zakończ, aby ukończyć pracę kreatora.
Rysunek 10. Ustaw listy rozwijane na kartach UPDATE i DELETE na wartość (Brak) (Kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Po ukończeniu kreatora znacznik deklaratywny CategoriesDataSource powinien wyglądać następująco:
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
Po utworzeniu i skonfigurowaniu CategoriesDataSource, wróć do pól szablonu CategoryNameItemTemplate, a następnie z inteligentnego tagu DropDownList kliknij łącze "Wybierz źródło danych". W kreatorze konfiguracji źródła danych wybierz CategoriesDataSource opcję z pierwszej listy rozwijanej i wybierz do użycia CategoryName dla wyświetlania oraz CategoryID jako wartość.
Rysunek 11. Powiązanie listy rozwijanej z listą CategoriesDataSource (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Na tym etapie lista rozwijana Categories DropDownList wyświetla wszystkie kategorie, ale jeszcze nie wybiera automatycznie odpowiedniej kategorii dla produktu, który jest powiązany z wierszem GridView. Aby to osiągnąć, musimy ustawić Categories DropDownList SelectedValue do wartości CategoryID produktu. Kliknij link Edytuj powiązania danych z poziomu inteligentnej etykiety DropDownList i skojarz właściwość SelectedValue z polem danych CategoryID, jak pokazano na rysunku 12.
Rysunek 12. Powiązanie wartości produktu CategoryID z właściwością DropDownList SelectedValue
Pozostaje jeszcze jeden problem: jeśli produkt nie ma CategoryID określonej wartości, instrukcja powiązania danych na SelectedValue spowoduje wyjątek. Jest to spowodowane tym, że lista rozwijana zawiera tylko elementy dotyczące kategorii i nie oferuje opcji dla tych produktów, które mają wartość bazy danych NULL dla CategoryID. Aby rozwiązać ten problem, ustaw właściwość DropDownList na wartość AppendDataBoundItemstrue i dodaj nowy element do listy DropDownList, pomijając właściwość Value w składni deklaratywnej. Oznacza to, że składnia deklaratywna listy Categories DropDownList wygląda następująco:
<asp:DropDownList ID="Categories" runat="server" AppendDataBoundItems="True"
DataSourceID="CategoriesDataSource" DataTextField="CategoryName"
DataValueField="CategoryID" SelectedValue='<%# Bind("CategoryID") %>'>
<asp:ListItem Value=">-- Select One --</asp:ListItem>
</asp:DropDownList>
Zwróć uwagę, jak <asp:ListItem Value=""> -- Select One -- ma swój Value atrybut jawnie ustawiony na pusty ciąg. Zapoznaj się z samouczkiem dostosowywania interfejsu do modyfikacji danych, aby uzyskać bardziej szczegółowe omówienie, dlaczego ten dodatkowy element listy rozwijanej jest potrzebny do obsługi NULL przypadku i dlaczego przypisanie właściwości Value do pustego ciągu znaków jest niezbędne.
Uwaga / Notatka
Istnieje tu potencjalny problem z wydajnością i skalowalnością, który warto wspomnieć. Ponieważ każdy wiersz ma DropDownList, które używa CategoriesDataSource jako źródła danych, metoda GetCategories w klasie CategoriesBLL będzie wywoływana n razy na każdą wizytę na stronie, gdzie n to liczba wierszy w GridView. Te n wywołania GetCategories skutkują n zapytaniami do bazy danych. Wpływ na bazę danych można zredukować poprzez buforowanie zwróconych kategorii w pamięci podręcznej na żądanie lub za pomocą warstwy buforującej przy użyciu zależności buforowania SQL lub bardzo krótkiego czasowego wygaśnięcia.
Krok 4. Kończenie pracy z interfejsem edycji
Wprowadziliśmy wiele zmian w szablonach GridView bez zatrzymywania się, aby zobaczyć nasze postępy. Znajdź chwilę, aby wyświetlić nasz postęp w przeglądarce. Jak pokazano na rysunku 13, każdy wiersz jest renderowany przy użyciu elementu ItemTemplate, który zawiera interfejs edytowania komórek.
Rysunek 13. Każdy wiersz kontrolki GridView można edytować (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Istnieje kilka drobnych problemów z formatowaniem, które należy wziąć pod uwagę w tym momencie. Najpierw należy pamiętać, że UnitPrice wartość zawiera cztery punkty dziesiętne. Aby rozwiązać ten problem, wróć do elementu UnitPrice TemplateFieldItemTemplate i z poziomu tagu smart TextBox kliknij link Edytuj powiązania danych. Następnie określ, że Text właściwość powinna być sformatowana jako liczba.
Rysunek 14. Formatowanie Text właściwości jako liczby
Po drugie, wyśrodkujmy pole wyboru w kolumnie Discontinued (zamiast wyrównywać je do lewej). Kliknij pozycję Edytuj kolumny z tagu inteligentnego GridView i wybierz pozycję Discontinued TemplateField z listy pól w lewym dolnym rogu. Zgłęb szczegóły w ItemStyle i ustaw właściwość HorizontalAlign na Center, jak pokazano na rysunku 15.
Rysunek 15: Wyśrodkuj Discontinued pole wyboru
Następnie dodaj kontrolkę ValidationSummary do strony i ustaw jej ShowMessageBox właściwość na true i jej ShowSummary właściwość na false. Dodaj również przyciski kontrolne Web, które po kliknięciu dokonają aktualizacji zmian użytkownika. W szczególności dodaj dwie kontrolki przycisku sieci Web, jedną powyżej kontrolki GridView i jedną poniżej, ustawiając obydwie właściwości kontrolek na "Update Products".
Ponieważ interfejs edycji kontrolki GridView jest zdefiniowany w obszarze TemplateFields ItemTemplate, te EditItemTemplate elementy są zbędne i mogą zostać usunięte.
Po wprowadzeniu powyższych zmian formatowania, dodaniu kontrolek przycisku oraz usunięciu niepotrzebnych elementów EditItemTemplate, składnia deklaratywna Twojej strony powinna wyglądać następująco:
<p>
<asp:Button ID="UpdateAllProducts1" runat="server" Text="Update Products" />
</p>
<p>
<asp:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsDataSource"
AllowPaging="True" AllowSorting="True">
<Columns>
<asp:TemplateField HeaderText="Product" SortExpression="ProductName">
<ItemTemplate>
<asp:TextBox ID="ProductName" runat="server"
Text='<%# Bind("ProductName") %>'></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
ControlToValidate="ProductName"
ErrorMessage="You must provide the product's name."
runat="server">*</asp:RequiredFieldValidator>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Category"
SortExpression="CategoryName">
<ItemTemplate>
<asp:DropDownList ID="Categories" runat="server"
AppendDataBoundItems="True"
DataSourceID="CategoriesDataSource"
DataTextField="CategoryName"
DataValueField="CategoryID"
SelectedValue='<%# Bind("CategoryID") %>'>
<asp:ListItem>-- Select One --</asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Price"
SortExpression="UnitPrice">
<ItemTemplate>
$<asp:TextBox ID="UnitPrice" runat="server" Columns="8"
Text='<%# Bind("UnitPrice", "{0:N}") %>'></asp:TextBox>
<asp:CompareValidator ID="CompareValidator1" runat="server"
ControlToValidate="UnitPrice"
ErrorMessage="You must enter a valid currency value.
Please omit any currency symbols."
Operator="GreaterThanEqual" Type="Currency"
ValueToCompare="0">*</asp:CompareValidator>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
<ItemTemplate>
<asp:CheckBox ID="Discontinued" runat="server"
Checked='<%# Bind("Discontinued") %>' />
</ItemTemplate>
<ItemStyle HorizontalAlign="Center" />
</asp:TemplateField>
</Columns>
</asp:GridView>
</p>
<p>
<asp:Button ID="UpdateAllProducts2" runat="server" Text="Update Products" />
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
<asp:ValidationSummary ID="ValidationSummary1" runat="server"
ShowMessageBox="True" ShowSummary="False" />
</p>
Rysunek 16 przedstawia tę stronę, gdy jest oglądana poprzez przeglądarkę po dodaniu kontrolek przycisków internetowych i wprowadzeniu zmian formatowania.
Rysunek 16. Strona zawiera teraz dwa przyciski Aktualizuj produkty (kliknij, aby wyświetlić obraz pełnowymiarowy)
Krok 5. Aktualizowanie produktów
Gdy użytkownik odwiedzi tę stronę, wprowadzi modyfikacje, a następnie kliknie jeden z dwóch przycisków Aktualizuj produkty. W tym momencie musimy w jakiś sposób zapisać wartości wprowadzone przez użytkownika dla każdego wiersza w ProductsDataTable wystąpieniu, a następnie przekazać je do metody BLL, która następnie przekaże to ProductsDataTable wystąpienie do metody DAL.UpdateWithTransaction Metoda UpdateWithTransaction, którą utworzyliśmy w poprzednim samouczku, gwarantuje, że partia zmian zostanie zaktualizowana jako operacja niepodzielna.
Utwórz metodę o nazwie BatchUpdate w pliku BatchUpdate.aspx.cs i dodaj następujący kod:
private void BatchUpdate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = productsAPI.GetProducts();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Find the ProductsRow instance in products that maps to gvRow
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsRow product = products.FindByProductID(productID);
if (product != null)
{
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateWithTransaction(products);
}
Ta metoda rozpoczyna się od pobrania wszystkich produktów do ProductsDataTable poprzez wywołanie metody BLL GetProducts. Następnie wylicza kolekcję ProductGridRows elementu GridView. Kolekcja Rows zawiera GridViewRow wystąpienie z każdego wiersza wyświetlanego w elemencie GridView. Ponieważ pokazujemy co najwyżej dziesięć wierszy na stronę, kolekcja GridView Rows nie będzie zawierać więcej niż dziesięciu elementów.
Dla każdego wiersza element ProductID jest pobierany z DataKeys kolekcji, a odpowiedni ProductsRow element jest wybierany z elementu ProductsDataTable. Cztery kontrolki wejściowe TemplateField są programowo przywoływane i ich wartości przypisane do ProductsRow właściwości instancji. Po zaktualizowaniu wartości wiersza kontrolki GridView, są one przekazywane do metody UpdateWithTransaction z BLL, która, jak pokazano w poprzednim samouczku, bezpośrednio wywołuje metodę UpdateWithTransaction w DAL.
Algorytm aktualizacji wsadowej używany na potrzeby tego samouczka aktualizuje każdy wiersz w ProductsDataTable elemecie GridView, niezależnie od tego, czy informacje o produkcie zostały zmienione. Chociaż takie ślepe aktualizacje nie są zwykle problemem z wydajnością, mogą prowadzić do nadmiarowych rekordów, jeśli przeprowadzasz inspekcję zmian w tabeli bazy danych. W samouczku Wykonywanie aktualizacji wsadowych zapoznaliśmy się z interfejsem aktualizacji wsadowej za pomocą elementu DataList i dodaliśmy kod, który zaktualizowałby tylko te rekordy, które zostały rzeczywiście zmodyfikowane przez użytkownika. Możesz swobodnie użyć technik z Wykonywanie zbiorczych aktualizacji do zaktualizowania kodu w tym samouczku, jeśli chcesz.
Uwaga / Notatka
Po powiązaniu źródła danych z kontrolką GridView za pomocą etykiety inteligentnej, program Visual Studio automatycznie przypisuje wartości klucza podstawowego źródła danych do właściwości kontrolki GridView DataKeyNames. Jeśli element ObjectDataSource nie został powiązany z kontrolką GridView za pomocą smart tagu GridView zgodnie z opisem w kroku 1, należy ręcznie ustawić właściwość GridView DataKeyNames na ProductID, aby uzyskać dostęp do ProductID wartości dla każdego wiersza za pośrednictwem DataKeys kolekcji.
Kod używany w systemie BatchUpdate jest podobny do tego używanego w metodach BLL UpdateProduct, a główna różnica polega na tym, że w metodach UpdateProduct pobiera się tylko jedno wystąpienie ProductRow z architektury. Kod, który przypisuje właściwości obiektu ProductRow, jest taki sam między metodami UpdateProducts a kodem w pętli foreach w elemencie BatchUpdate, co jest ogólnym wzorcem.
Aby ukończyć ten samouczek, musimy wywołać metodę BatchUpdate po kliknięciu jednego z przycisków Aktualizuj produkty. Utwórz programy obsługi zdarzeń dla Click zdarzeń tych dwóch kontrolek typu Button i dodaj następujący kod w programach obsługi zdarzeń.
BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message",
"alert('The products have been updated.');", true);
Najpierw wykonano połączenie do BatchUpdate. Następnie ClientScript property jest używany do wstrzykiwania kodu JavaScript, który będzie wyświetlał pole komunikatu z informacją "Produkty zostały zaktualizowane".
Pośmiń minutę na przetestowanie tego kodu. Odwiedź BatchUpdate.aspx za pomocą przeglądarki, edytuj pewną liczbę wierszy i kliknij jeden z przycisków Aktualizuj produkty. Przy założeniu, że nie ma żadnych błędów walidacji danych wejściowych, powinien zostać wyświetlony komunikat z informacją o zaktualizowaniu produktów. Aby zweryfikować niepodzielność aktualizacji, rozważ dodanie przypadkowego ograniczenia CHECK, na przykład takiego, które zabrania wartości UnitPrice 1234.56. Następnie z BatchUpdate.aspx pliku zmodyfikuj liczbę rekordów, upewniając się, że ustawiono jedną z wartości produktu UnitPrice na wartość zabronioną (1234.56). Powinno to spowodować błąd po kliknięciu przycisku Aktualizuj produkty, przy czym inne zmiany w tej operacji wsadowej zostaną cofnięte do oryginalnych wartości.
Metoda alternatywnaBatchUpdate
Metoda BatchUpdate , którą właśnie zbadaliśmy, pobiera wszystkie produkty z metody BLL, GetProducts a następnie aktualizuje tylko te rekordy, które są wyświetlane w kontrolce GridView. Takie podejście jest idealne, jeśli GridView nie używa stronicowania, ale jeśli jest używane, może być setki, tysiące lub dziesiątki tysięcy produktów, ale w GridView będą tylko dziesięć wierszy. W takim przypadku pobieranie wszystkich produktów z bazy danych tylko po to, aby zmodyfikować 10 z nich, nie jest optymalne.
W przypadku tych typów sytuacji rozważ użycie następującej BatchUpdateAlternate metody:
private void BatchUpdateAlternate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Create a new ProductRow instance
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsDataTable currentProductDataTable =
productsAPI.GetProductByProductID(productID);
if (currentProductDataTable.Rows.Count > 0)
{
Northwind.ProductsRow product = currentProductDataTable[0];
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
// Import the ProductRow into the products DataTable
products.ImportRow(product);
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateProductsWithTransaction(products);
}
BatchMethodAlternate rozpoczyna się od utworzenia nowego pustego ProductsDataTable o nazwie products. Następnie iteruje przez kolekcję GridView Rows, aby dla każdego wiersza pobrać szczegółowe informacje o produkcie, używając metody BLL GetProductByProductID(productID). Pobrane ProductsRow wystąpienie ma zaktualizowane właściwości w taki sam sposób jak BatchUpdate, jednak po zaktualizowaniu wiersza jest importowane do products``ProductsDataTable poprzez metodę ImportRow(DataRow) w obiekcie DataTable.
Po zakończeniu pętli foreach, products zawiera jedno wystąpienie ProductsRow dla każdego wiersza w GridView. Od momentu, gdy każde wystąpienie ProductsRow zostało dodane do products (zamiast zaktualizowane), jeśli bez zastanowienia przekażemy je do metody UpdateWithTransaction, ProductsTableAdapter spróbuje wstawić każdy rekord do bazy danych. Zamiast tego musimy określić, że każdy z tych wierszy został zmodyfikowany (nie został dodany).
Można to osiągnąć, dodając nową metodę do BLL o nazwie UpdateProductsWithTransaction.
UpdateProductsWithTransaction, jak pokazano poniżej, ustawia RowState dla każdej z instancji ProductsRow w ProductsDataTable na Modified, a następnie przekazuje ProductsDataTable do metody UpdateWithTransaction w DAL.
public int UpdateProductsWithTransaction(Northwind.ProductsDataTable products)
{
// Mark each product as Modified
products.AcceptChanges();
foreach (Northwind.ProductsRow product in products)
product.SetModified();
// Update the data via a transaction
return UpdateWithTransaction(products);
}
Podsumowanie
Funkcja GridView zapewnia wbudowane funkcje edytowania wierszy, ale nie obsługuje tworzenia w pełni edytowalnych interfejsów. Jak pokazano w tym samouczku, takie interfejsy są możliwe, ale wymagają pewnego nakładu pracy. Aby utworzyć GridView, w którym można edytować każdy wiersz, musimy przekonwertować pola GridView na pola TemplateFields i zdefiniować interfejs edycji w ItemTemplate. Ponadto na stronie należy dodać kontrolki webowe typu "Update All", oddzielone od kontrolki GridView. Te procedury obsługi zdarzeń przycisków Click muszą wyliczyć kolekcję GridView Rows, przechowywać zmiany w ProductsDataTable obiekcie i przekazać zaktualizowane informacje do odpowiedniej metody BLL.
W następnym samouczku pokażemy, jak utworzyć interfejs do wsadowego usuwania. W szczególności, każdy wiersz w GridView będzie zawierać pole wyboru, a zamiast przycisków w stylu Aktualizuj Wszystkie będziemy mieć przyciski Usuń zaznaczone wiersze.
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 go uzyskać pod adresem mitchell@4GuysFromRolla.com.
Specjalne podziękowania
Ta seria samouczków została omówiona przez wielu przydatnych recenzentów. Główni recenzenci tego samouczka to Teresa Murphy i David Suru. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, napisz do mnie na adres mitchell@4GuysFromRolla.com.