Aktualizowanie w partiach (C#)
Dowiedz się, jak zaktualizować wiele rekordów bazy danych w ramach jednej operacji. W warstwie interfejsu użytkownika tworzymy kontrolkę GridView, w której można edytować każdy wiersz. W warstwie dostępu do danych opakowujemy wiele operacji aktualizacji w ramach transakcji, aby upewnić się, że wszystkie aktualizacje zostaną wycofane lub wszystkie aktualizacje zostaną wycofane.
Wprowadzenie
W poprzednim samouczku pokazano, jak rozszerzyć warstwę dostępu do danych, aby dodać obsługę transakcji bazy danych. Transakcje bazy danych gwarantują, że seria instrukcji modyfikacji danych będzie traktowana jako jedna operacja niepodzielna, co gwarantuje, że wszystkie modyfikacje zakończy się niepowodzeniem lub wszystkie zostaną wykonane pomyślnie. Dzięki tej funkcji dal niskiego poziomu jesteśmy gotowi zwrócić uwagę na tworzenie interfejsów modyfikacji danych wsadowych.
W tym samouczku utworzymy element 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 kolumny 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 siatceView jest edytowalny (kliknij, aby wyświetlić obraz pełnowymiarowy)
Zacznijmy!
Uwaga
W samouczku Dotyczącym wykonywania usługi Batch Aktualizacje utworzyliśmy interfejs edycji wsadowej przy użyciu kontrolki DataList. Ten samouczek różni się od poprzedniego w tym, że używa elementu GridView, a aktualizacja wsadowa jest wykonywana w zakresie transakcji. Po ukończeniu tego samouczka zachęcamy do powrotu do wcześniejszego samouczka i zaktualizowania go do korzystania z funkcji związanych z transakcjami bazy danych dodanych w poprzednim samouczku.
Badanie kroków edytowania wszystkich wierszy 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 wierszy są renderowane przy użyciu interfejsów edycji. W przypadku obiektów BoundFields interfejs edycji to TextBox, którego Text
właściwość ma przypisaną wartość pola danych określonego przez właściwość BoundField.DataField
W przypadku obiektów TemplateFields EditItemTemplate
element jest używany zamiast ItemTemplate
elementu .
Pamiętaj, że przepływ pracy edytowania 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 umieszcza dane w siatce. Po kliknięciu przycisku Anuluj wiersza po powrocie EditIndex
zostanie ustawiona wartość -1
przed ponownym powiązaniem danych z siatką. Ponieważ wiersze kontrolki GridView zaczynają indeksować od zera, ustawienie EditIndex
-1
ma wpływ na wyświetlanie elementu GridView w trybie tylko do odczytu.
Właściwość EditIndex
działa dobrze w przypadku edycji poszczególnych wierszy, ale nie jest przeznaczona do edycji wsadowej. Aby można było edytować cały element GridView, musimy renderować każdy wiersz 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 ze swoim interfejsem edycji zdefiniowanym w elemecie ItemTemplate
.
W kolejnych kilku krokach utworzymy całkowicie edytowalny element GridView. W kroku 1 zaczniemy od utworzenia elementu GridView i jego obiektuDataSource oraz przekonwertowania pól BoundFields i CheckBoxField na pola szablonów. W krokach 2 i 3 przeniesiemy interfejsy edycji z pola szablonów EditItemTemplate
do ich ItemTemplate
elementów.
Krok 1. Wyświetlanie informacji o produkcie
Zanim zaczniemy się martwić o utworzenie elementu GridView, w którym można edytować wiersze, zacznijmy od po prostu wyświetlenia informacji o produkcie. BatchUpdate.aspx
Otwórz stronę w folderze BatchData
i przeciągnij element GridView z przybornika do Projektant. Ustaw element GridView na ID
ProductsGrid
i z jego tagu inteligentnego wybierz powiązanie go 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 pełnowymiarowy)
Rysunek 3. Pobieranie danych produktu przy użyciu GetProducts
metody (kliknij, aby wyświetlić obraz pełnowymiarowy)
Podobnie jak w przypadku kontrolki GridView, funkcje modyfikacji obiektu ObjectDataSource zostały zaprojektowane tak, aby działały w poszczególnych wierszach. Aby zaktualizować zestaw rekordów, musimy napisać trochę kodu w klasie za ASP.NET strony kodu, która wsaduje dane i przekazuje je do usługi BLL. W związku z tym ustaw listy rozwijane na kartach UPDATE, INSERT i DELETE obiektu ObjectDataSource na wartość (Brak). Kliknij przycisk Zakończ, aby zakończyć kreatora.
Rysunek 4. Ustawianie Drop-Down Listy na kartach UPDATE, INSERT i DELETE na wartość (Brak) (Kliknij, aby wyświetlić obraz pełnowymiarowy)
Po ukończeniu pracy Kreatora konfigurowania ź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 elemecie GridView. W tym samouczku zezwalajmy tylko użytkownikowi na wyświetlanie i edytowanie nazwy produktu, kategorii, ceny i stanu zakończenia. Usuń wszystkie pola , ProductName
, CategoryName
, UnitPrice
i Discontinued
i zmień nazwę HeaderText
właściwości pierwszych trzech pól odpowiednio na Product, Category i Price. Na koniec zaznacz pola wyboru Włącz stronicowanie i Włącz sortowanie w tagu inteligentnym GridView.
W tym momencie element GridView ma trzy pola granic (ProductName
, CategoryName
i UnitPrice
) i CheckBoxField (Discontinued
). Musimy przekonwertować te cztery pola na pola templateFields, a następnie przenieść interfejs edycji z pola szablonu EditItemTemplate
do elementu ItemTemplate
.
Uwaga
Zapoznaliśmy się z tworzeniem i dostosowywaniem elementów TemplateFields w samouczku Dostosowywanie interfejsu modyfikacji danych . Omówimy kroki konwertowania pól Powiązanych i CheckBoxField na pola szablonów i definiowania ich interfejsów edycji w swoich ItemTemplate
elementach, ale jeśli utkniesz lub potrzebujesz odświeżenia, nie wahaj się odwołać do tego wcześniejszego samouczka.
W tagu inteligentnym GridView kliknij link Edytuj kolumny, aby otworzyć okno dialogowe Pola. Następnie wybierz każde pole i kliknij link 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 polem TemplateField, możemy przenieść interfejs edycji z EditItemTemplate
s do ItemTemplate
s.
Krok 2. TworzenieProductName
UnitPrice
iDiscontinued
edytowanie interfejsów
ProductName
Tworzenie interfejsów , UnitPrice
i Discontinued
edycji jest tematem tego kroku i jest dość proste, ponieważ każdy interfejs jest już zdefiniowany w szablonie TemplateField s EditItemTemplate
. Tworzenie interfejsu CategoryName
edycji jest nieco bardziej zaangażowane, ponieważ musimy utworzyć listę rozwijaną odpowiednich kategorii. Ten CategoryName
interfejs edycji jest rozwiązywany w kroku 3.
Zacznijmy od pola szablonu ProductName
. Kliknij link Edytuj szablony z tagu inteligentnego GridView i przejdź do szczegółów pola szablonów ProductName
EditItemTemplate
. Wybierz pole tekstowe, skopiuj je do schowka, a następnie wklej je do pola szablonu ProductName
ItemTemplate
. Zmień właściwość ProductName
TextBox na ID
.
Następnie dodaj element RequiredFieldValidator do elementu ItemTemplate
, aby upewnić się, że użytkownik podaje wartość dla każdej nazwy produktu. ControlToValidate
Ustaw właściwość na ProductName, ErrorMessage
właściwość na Wartość Musisz podać nazwę produktu. Text
i właściwość na *. Po dodaniu tych dodatków do ekranu powinien wyglądać podobnie do rysunku ItemTemplate
6.
Rysunek 6. Pole szablonu ProductName
zawiera teraz pole tekstowe i element RequiredFieldValidator (kliknij, aby wyświetlić obraz pełnowymiarowy)
W przypadku interfejsu edycji UnitPrice
zacznij od skopiowania pola TextBox z folderu EditItemTemplate
do elementu ItemTemplate
. Następnie umieść wartość $ przed polem TextBox i ustaw jej ID
właściwość na UnitPrice i jej Columns
właściwość 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
poprawności na UnitPrice, jej ErrorMessage
właściwość na Wartość Musisz wprowadzić prawidłową wartość waluty. Pomiń wszystkie symbole waluty., jej Text
właściwość na *, jej Type
właściwość na , jej Operator
właściwość na Currency
, i jej ValueToCompare
właściwość na GreaterThanEqual
0 .
Rysunek 7. Dodawanie elementu CompareValidator w celu upewnienia się, że wprowadzona cena jest wartością innej niż ujemna waluta (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
W polu Discontinued
TemplateField można użyć pola checkbox już zdefiniowanego w elemecie ItemTemplate
. Po prostu ustaw jego ID
wartość na Wartość Wycofano, a jej Enabled
właściwość na true
.
Krok 3. Tworzenie interfejsu edycjiCategoryName
Interfejs edycji w elemecie CategoryName
TemplateField zawiera EditItemTemplate
pole TextBox, które wyświetla wartość CategoryName
pola danych. Musimy zastąpić to listą rozwijaną, która zawiera listę możliwych kategorii.
Uwaga
Samouczek Dostosowywanie interfejsu modyfikacji danych zawiera bardziej szczegółową i kompletną dyskusję na temat dostosowywania szablonu w celu uwzględnienia listy rozwijanej w przeciwieństwie do pola TextBox. Kroki opisane w tym miejscu są kompletne, ale są prezentowane w sposób uproszczony. 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 do elementu CategoryName
TemplateField s ItemTemplate
, ustawiając wartość ID
Categories
. Na tym etapie zwykle definiujemy źródło danych DropDownLists za pomocą tagu inteligentnego, tworząc nowy obiekt ObjectDataSource. Spowoduje to jednak dodanie obiektu ObjectDataSource w obiekcie ItemTemplate
, co spowoduje utworzenie wystąpienia ObjectDataSource dla każdego wiersza kontrolki GridView. Zamiast tego utwórzmy obiekt ObjectDataSource poza polami TemplateFields kontrolki GridView. Zakończ edycję szablonu i przeciągnij element ObjectDataSource z przybornika do Projektant pod obiektem ProductsDataSource
ObjectDataSource. Nadaj nowemu obiektowi nazwę ObjectDataSource CategoriesDataSource
i skonfiguruj ją tak, aby korzystała CategoriesBLL
z metody klasy s GetCategories
.
Rysunek 8. Konfigurowanie obiektu ObjectDataSource do używania CategoriesBLL
klasy (kliknij, aby wyświetlić obraz w pełnym rozmiarze)
Rysunek 9. Pobieranie danych kategorii przy użyciu GetCategories
metody (kliknij, aby wyświetlić obraz pełnowymiarowy)
Ponieważ ta właściwość ObjectDataSource jest używana tylko do pobierania danych, ustaw listy rozwijane na kartach UPDATE i DELETE na wartość (Brak). Kliknij przycisk Zakończ, aby zakończyć kreatora.
Rysunek 10. Ustawianie Drop-Down Listy na kartach UPDATE i DELETE na wartość (Brak) (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Po zakończeniu pracy kreatora CategoriesDataSource
znacznik deklaratywny 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 pola szablonu CategoryName
ItemTemplate
, a następnie z tagu inteligentnego DropDownList kliknij link Wybierz źródło danych. W kreatorze Konfiguracja źródła danych wybierz CategoriesDataSource
opcję z pierwszej listy rozwijanej i wybierz opcję, która ma być CategoryName
używana do wyświetlania i 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 Categories
Lista rozwijana zawiera listę wszystkich kategorii, ale nie wybiera ona jeszcze automatycznie odpowiedniej kategorii dla produktu powiązanego z wierszem GridView. Aby to osiągnąć, musimy ustawić wartość Categories
listy DropDownList na SelectedValue
CategoryID
wartość produktu. Kliknij link Edit DataBindings (Edytuj powiązanie danych) z tagu inteligentnego DropDownList i skojarz SelectedValue
właściwość z polem CategoryID
danych, 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 dla SelectedValue
elementu spowoduje wyjątek. Wynika to z tego, że lista DropDownList zawiera tylko elementy kategorii i nie oferuje opcji dla tych produktów, które mają NULL
wartość bazy danych dla CategoryID
. Aby rozwiązać ten problem, ustaw właściwość DropDownList na AppendDataBoundItems
true
i dodaj nowy element do listy DropDownList, pomijając Value
właściwość ze składni deklaratywnej. Oznacza to, że Categories
składnia deklaratywna listy 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ę, <asp:ListItem Value="">
że właściwość -- Select One -- ma jawnie Value
ustawiony atrybut na pusty ciąg. Zapoznaj się z samouczkiem Dostosowywanie interfejsu modyfikacji danych , aby dowiedzieć się więcej na temat tego, dlaczego ten dodatkowy element DropDownList jest potrzebny do obsługi NULL
sprawy i dlaczego przypisanie Value
właściwości do pustego ciągu jest niezbędne.
Uwaga
W tym miejscu istnieje potencjalny problem z wydajnością i skalowalnością, który warto wspomnieć. Ponieważ każdy wiersz zawiera listę DropDownList, która używa CategoriesDataSource
elementu jako źródła danych, CategoriesBLL
metoda klasy s GetCategories
będzie wywoływana n razy na wizytę strony, gdzie n jest liczbą wierszy w klasie GridView. Te n wywołania powodują, że GetCategories
n zapytań do bazy danych. Ten wpływ na bazę danych można zmniejszyć przez buforowanie zwróconych kategorii w pamięci podręcznej dla poszczególnych żądań lub za pośrednictwem warstwy buforowania przy użyciu zależności buforowania SQL lub bardzo krótkiego wygaśnięcia na podstawie czasu.
Krok 4. Kończenie pracy z interfejsem edycji
Wprowadziliśmy szereg zmian w szablonach kontrolki GridView bez wstrzymowania w celu wyświetlenia postępu. Poświęć chwilę, aby wyświetlić postęp w przeglądarce. Jak pokazano na rysunku 13, każdy wiersz jest renderowany przy użyciu elementu ItemTemplate
, który zawiera interfejs edycji komórek.
Rysunek 13. Każdy wiersz GridView jest edytowalny (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
W tym momencie należy zadbać o kilka drobnych problemów z formatowaniem. Najpierw należy pamiętać, że UnitPrice
wartość zawiera cztery punkty dziesiętne. Aby rozwiązać ten problem, wróć do elementu UnitPrice
TemplateField s ItemTemplate
, a następnie z tagu inteligentnego TextBox kliknij link Edit DataBindings (Edytuj powiązanie 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ównać ją do lewej). Kliknij pozycję Edytuj kolumny z tagu inteligentnego GridView i wybierz pozycję Discontinued
TemplateField z listy pól w lewym dolnym rogu. Przejdź do ItemStyle
szczegółów i ustaw HorizontalAlign
właściwość na Center, jak pokazano na rysunku 15.
Rysunek 15. Wyśrodkowanie Discontinued
pola 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ż kontrolki Sieci Web przycisku, które po kliknięciu spowodują zaktualizowanie zmian użytkownika. W szczególności dodaj dwie kontrolki Sieci Web przycisku, jeden powyżej kontrolki GridView i jeden poniżej, ustawiając obie właściwości kontrolek Text
na Wartość Aktualizuj produkty.
Ponieważ interfejs edycji kontrolki GridView jest zdefiniowany w swoich polach TemplateFields ItemTemplate
, EditItemTemplate
obiekty są zbędne i mogą zostać usunięte.
Po wprowadzeniu powyższych zmian formatowania, dodaniu kontrolek Przycisk i usunięciu niepotrzebnych EditItemTemplate
elementów składni deklaratywnej 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ę po wyświetleniu za pośrednictwem przeglądarki po dodaniu kontrolek Sieci Web przycisku i wprowadzeniu zmian formatowania.
Rysunek 16. Strona zawiera teraz dwa przyciski Aktualizuj produkty (kliknij, aby wyświetlić obraz w pełnym rozmiarze)
Krok 5. Aktualizowanie produktów
Gdy użytkownik odwiedzi tę stronę, wprowadzi zmiany, 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óra została utworzona w poprzednim samouczku, gwarantuje, że partia zmian zostanie zaktualizowana jako operacja niepodzielna.
Utwórz metodę o nazwie BatchUpdate
w BatchUpdate.aspx.cs
pliku 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 z powrotem do ProductsDataTable
metody BLL za pośrednictwem wywołania metody BLL GetProducts
. Następnie wylicza ProductGrid
kolekcję GridViewRows
. Kolekcja Rows
zawiera GridViewRow
wystąpienie dla każdego wiersza wyświetlanego w siatce GridView. Ponieważ pokazujemy co najwyżej dziesięć wierszy na stronę, kolekcja kontrolki Rows
GridView 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łyane i ich wartości przypisane do ProductsRow
właściwości wystąpienia. Po zaktualizowaniu wartości ProductsDataTable
poszczególnych wierszy GridView zostanie ona przekazana do metody BLL UpdateWithTransaction
, która, jak pokazano w poprzednim samouczku, po prostu wywołuje metodę DAL UpdateWithTransaction
w dół.
Algorytm aktualizacji wsadowej używany w tym samouczku aktualizuje każdy wiersz w ProductsDataTable
obiekcie odpowiadający wierszowi w siatce 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. Po powrocie do samouczka Performing Batch Aktualizacje omówiliśmy interfejs aktualizacji wsadowej za pomocą elementu DataList i dodaliśmy kod, który będzie aktualizował tylko te rekordy, które zostały faktycznie zmodyfikowane przez użytkownika. W razie potrzeby możesz użyć technik wykonywanych w usłudze Batch Aktualizacje, aby zaktualizować kod w tym samouczku.
Uwaga
Po powiązaniu źródła danych z obiektem GridView za pomocą tagu inteligentnego program Visual Studio automatycznie przypisuje wartości klucza podstawowego źródła danych do właściwości GridView DataKeyNames
. Jeśli element ObjectDataSource nie został powiązany z kontrolką GridView za pośrednictwem tagu inteligentnego GridView zgodnie z opisem w kroku 1, należy ręcznie ustawić właściwość GridView DataKeyNames
na Wartość ProductID, aby uzyskać dostęp do ProductID
wartości dla każdego wiersza za pośrednictwem DataKeys
kolekcji.
Kod używany w BatchUpdate
systemie jest podobny do tego, który jest używany w metodach BLL UpdateProduct
, główną różnicą jest to, że w UpdateProduct
metodach tylko jedno ProductRow
wystąpienie jest pobierane z architektury. Kod, który przypisuje właściwości obiektu ProductRow
, jest taki sam między UpdateProducts
metodami a kodem w pętli w BatchUpdate
elemecie foreach
, 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 Przycisk 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 wywołanie metody .BatchUpdate
Następnie element jest używany do wstrzykiwania kodu JavaScript, ClientScript property
który wyświetli pole komunikatu z informacją o zaktualizowaniu produktów.
Poświęć chwilę na przetestowanie tego kodu. Odwiedź BatchUpdate.aspx
przeglądarkę, edytuj kilka wierszy i kliknij jeden z przycisków Aktualizuj produkty. Przy założeniu, że nie ma żadnych błędów walidacji danych wejściowych, powinna zostać wyświetlona skrzynka komunikatów z informacją o zaktualizowaniu produktów. Aby sprawdzić niepodzielność aktualizacji, rozważ dodanie ograniczenia losowego CHECK
, na przykład takiego, który nie zezwala UnitPrice
na wartości 1234,56. Następnie z BatchUpdate.aspx
pliku zmodyfikuj liczbę rekordów, ustawiając jedną z wartości produktu UnitPrice
na niedozwoloną wartość (1234,56 ). Powinno to spowodować błąd po kliknięciu przycisku Aktualizuj produkty z innymi zmianami podczas tej operacji wsadowej wycofanej do ich 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 element GridView nie używa stronicowania, ale jeśli tak, może istnieć setki, tysiące lub dziesiątki tysięcy produktów, ale tylko dziesięć wierszy w siatce. W takim przypadku pobranie wszystkich produktów z bazy danych tylko w celu zmodyfikowania 10 z nich jest mniejsze niż idealne.
W przypadku tego typu 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 przechodzi przez kolekcję GridView Rows
i dla każdego wiersza uzyskuje określone informacje o produkcie przy użyciu metody BLL GetProductByProductID(productID)
. Pobrane ProductsRow
wystąpienie ma właściwości zaktualizowane w taki sam sposób jak BatchUpdate
, ale po zaktualizowaniu wiersza jest importowane do products``ProductsDataTable
obiektu za pośrednictwem metody DataTableImportRow(DataRow)
.
Po zakończeniu foreach
products
pętli zawiera jedno ProductsRow
wystąpienie dla każdego wiersza w pętli GridView. Ponieważ każde z ProductsRow
wystąpień zostało dodane do products
elementu (zamiast aktualizacji), jeśli ślepo przekażemy je do UpdateWithTransaction
metody , ProductsTableAdapter
metoda 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
, pokazany poniżej, ustawia RowState
każdy z ProductsRow
wystąpień w ProductsDataTable
obiekcie na Modified
, a następnie przekazuje element ProductsDataTable
do metody DAL UpdateWithTransaction
.
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
Kontrolka GridView zapewnia wbudowane funkcje edytowania poszczególnych wierszy, ale nie obsługuje tworzenia w pełni edytowalnych interfejsów. Jak pokazano w tym samouczku, takie interfejsy są możliwe, ale wymagają trochę pracy. Aby utworzyć obiekt GridView, w którym można edytować każdy wiersz, musimy przekonwertować pola kontrolki GridView na pola templatefield i zdefiniować interfejs edycji w obiekcie ItemTemplate
s. Ponadto do strony należy dodać kontrolki Sieci Web Typu wszystkie - typ , niezależnie od kontrolki GridView. Te programy obsługi zdarzeń przycisków Click
muszą wyliczyć kolekcję GridView Rows
, zapisać zmiany w ProductsDataTable
obiekcie i przekazać zaktualizowane informacje do odpowiedniej metody BLL.
W następnym samouczku zobaczymy, jak utworzyć interfejs do usuwania wsadowego. W szczególności każdy wiersz GridView będzie zawierać pole wyboru, a zamiast przycisków Aktualizuj wszystkie - typ będziemy mieli przyciski Usuń wybrane 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 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 Teresa Murphy i David Suru. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi wiersz pod adresemmitchell@4GuysFromRolla.com .