Udostępnij za pośrednictwem


Wstawianie w partiach (VB)

Autor: Scott Mitchell

Pobierz plik PDF

Dowiedz się, jak wstawić wiele rekordów bazy danych w jednej operacji. W warstwie interfejsu użytkownika rozszerzymy kontrolkę GridView, aby umożliwić użytkownikowi wprowadzanie wielu nowych rekordów. W warstwie dostępu do danych opakowujemy wiele operacji wstawiania w ramach transakcji, aby upewnić się, że wszystkie operacje wstawiania kończą się powodzeniem lub wszystkie operacje wstawiania zostaną wycofane.

Wprowadzenie

W samouczku dotyczącym aktualizacji usługi Batch przyjrzeliśmy się dostosowywaniu kontrolki GridView w celu przedstawienia interfejsu, w którym można edytować wiele rekordów. Użytkownik odwiedzający stronę może wprowadzić serię zmian, a następnie, za pomocą jednego przycisku, przeprowadzić aktualizację wsadową. W sytuacjach, w których użytkownicy często aktualizują wiele rekordów w jednym miejscu, taki interfejs może zapisywać niezliczone kliknięcia i przełączniki kontekstowe klawiatury do myszy w porównaniu z domyślnymi funkcjami edycji poszczególnych wierszy, które zostały po raz pierwszy zbadane w samouczku Omówienie wstawiania , aktualizowania i usuwania danych .

Tę koncepcję można również zastosować podczas dodawania rekordów. Załóżmy, że w firmie Northwind Traders często otrzymujemy przesyłki od dostawców, którzy zawierają wiele produktów dla określonej kategorii. Na przykład możemy otrzymać przesyłkę sześciu różnych produktów herbacianych i kawy od Firmy Tokio Traders. Jeśli użytkownik wprowadzi sześć produktów pojedynczo za pomocą kontrolki DetailsView, będzie musiał wybrać wiele tych samych wartości po raz kolejny: będzie musiał wybrać tę samą kategorię (Napoje), tego samego dostawcę (Tokio Traders), tę samą wartość przerwaną (Fałsz) i te same jednostki w wartości zamówienia (0). Ten powtarzalny wpis danych jest nie tylko czasochłonny, ale jest podatny na błędy.

Przy odrobinie pracy możemy utworzyć interfejs wstawiania wsadowego, który umożliwia użytkownikowi wybranie dostawcy i kategorii raz, wprowadzenie serii nazw produktów i cen jednostkowych, a następnie kliknięcie przycisku, aby dodać nowe produkty do bazy danych (zobacz Rysunek 1). Po dodaniu każdego produktu pola danych ProductName i UnitPrice są przypisywane wartości wprowadzone w polach TextBoxes, podczas gdy jej CategoryID wartości i SupplierID są przypisywane wartości z listy DropDownLists u góry formularza. Wartości Discontinued i UnitsOnOrder są ustawione odpowiednio na wartości zakodowane False na twardo i 0.

Interfejs wstawiania wsadowego

Rysunek 1. Interfejs wstawiania wsadowego (kliknij, aby wyświetlić obraz pełnowymiarowy)

W tym samouczku utworzymy stronę, która implementuje interfejs wstawiania wsadowego pokazany na rysunku 1. Podobnie jak w przypadku poprzednich dwóch samouczków, opakowujemy wstawiania w zakresie transakcji, aby zapewnić niepodzielność. Zacznijmy!

Krok 1. Tworzenie interfejsu wyświetlania

Ten samouczek składa się z jednej strony podzielonej na dwa regiony: region wyświetlania i region wstawiania. Interfejs wyświetlania, który utworzymy w tym kroku, pokazuje produkty w elemecie GridView i zawiera przycisk zatytułowany Przetwarzanie wysyłki produktu. Po kliknięciu tego przycisku interfejs wyświetlania jest zastępowany interfejsem wstawiania, który jest wyświetlany na rysunku 1. Interfejs wyświetlania jest zwracany po kliknięciu przycisków Dodaj produkty z przesyłki lub Anulowania. Utworzymy interfejs wstawiania w kroku 2.

Podczas tworzenia strony, która ma dwa interfejsy, tylko jeden z nich jest widoczny jednocześnie, każdy interfejs jest zwykle umieszczany w kontrolce Sieci Web Panelu, która służy jako kontener dla innych kontrolek. W związku z tym nasza strona będzie miała dwa kontrolki Panel jeden dla każdego interfejsu.

Zacznij od otwarcia BatchInsert.aspx strony w BatchData folderze i przeciągnij panel z przybornika do Projektant (patrz Rysunek 2). Ustaw właściwość Panel na IDDisplayInterface. Podczas dodawania panelu do Projektant jego Height właściwości i Width są ustawione odpowiednio na 50 pikseli i 125 pikseli. Wyczyść te wartości właściwości z okno Właściwości.

Przeciągnij panel z przybornika na Projektant

Rysunek 2. Przeciągnij panel z przybornika na Projektant (kliknij, aby wyświetlić obraz pełnowymiarowy)

Następnie przeciągnij kontrolkę Button i GridView do panelu. Ustaw właściwość Button ID na ProcessShipment i jej Text właściwość na Process Product Shipment. Ustaw właściwość GridView ID na ProductsGrid i z jego tagu inteligentnego powiąż ją z nowym obiektem ObjectDataSource o nazwie ProductsDataSource. Skonfiguruj obiekt ObjectDataSource, aby ściągnąć dane z ProductsBLL metody klasy s GetProducts . Ponieważ ten element GridView jest używany tylko do wyświetlania danych, ustaw listę rozwijaną na kartach UPDATE, INSERT i DELETE na wartość (Brak). Kliknij przycisk Zakończ, aby ukończyć pracę kreatora Konfigurowanie źródła danych.

Wyświetlanie danych zwróconych z metody GetProducts klasy ProductsBLL

Rysunek 3. Wyświetlanie danych zwróconych z ProductsBLL metody klasy GetProducts (kliknij, aby wyświetlić obraz pełnowymiarowy)

Ustaw Drop-Down Listy na kartach UPDATE, INSERT i DELETE na wartość (Brak)

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 ObjectDataSource program Visual Studio doda pola BoundFields i CheckBoxField dla pól danych produktu. Usuń wszystkie, ale ProductNamepola , CategoryName, SupplierName, UnitPricei Discontinued . Możesz swobodnie wprowadzać wszelkie dostosowania estetyki. Postanowiłem sformatować UnitPrice pole jako wartość waluty, zmienić kolejność pól i zmienić nazwę kilku wartości pól HeaderText . Skonfiguruj również kontrolkę GridView tak, aby zawierała obsługę stronicowania i sortowania, zaznaczając pola wyboru Włącz stronicowanie i Włącz sortowanie w tagu inteligentnym GridView.

Po dodaniu kontrolek Panel, Button, GridView i ObjectDataSource oraz dostosowywaniu pól GridView znacznik deklaratywny strony powinien wyglądać podobnie do następującego:

<asp:Panel ID="DisplayInterface" runat="server">
    <p>
        <asp:Button ID="ProcessShipment" runat="server" 
            Text="Process Product Shipment" /> 
    </p>
    <asp:GridView ID="ProductsGrid" runat="server" AllowPaging="True" 
        AllowSorting="True" AutoGenerateColumns="False" 
        DataKeyNames="ProductID" DataSourceID="ProductsDataSource">
        <Columns>
            <asp:BoundField DataField="ProductName" HeaderText="Product" 
                SortExpression="ProductName" />
            <asp:BoundField DataField="CategoryName" HeaderText="Category" 
                ReadOnly="True" SortExpression="CategoryName" />
            <asp:BoundField DataField="SupplierName" HeaderText="Supplier" 
                ReadOnly="True" SortExpression="SupplierName" />
            <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
                HeaderText="Price" HtmlEncode="False" 
                SortExpression="UnitPrice">
                <ItemStyle HorizontalAlign="Right" />
            </asp:BoundField>
            <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" 
                SortExpression="Discontinued">
                <ItemStyle HorizontalAlign="Center" />
            </asp:CheckBoxField>
        </Columns>
    </asp:GridView>
    <asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
        OldValuesParameterFormatString="original_{0}"
        SelectMethod="GetProducts" TypeName="ProductsBLL">
    </asp:ObjectDataSource>
</asp:Panel>

Należy pamiętać, że znaczniki przycisku i kontrolki GridView są wyświetlane w tagach otwierania i zamykania <asp:Panel> . Ponieważ te kontrolki znajdują się w DisplayInterface panelu, możemy je ukryć, ustawiając właściwość Panel Visible na False. Krok 3 analizuje programowo zmianę właściwości Panel w Visible odpowiedzi na kliknięcie przycisku, aby pokazać jeden interfejs, ukrywając drugi.

Poświęć chwilę, aby wyświetlić postęp w przeglądarce. Jak pokazano na rysunku 5, powinien zostać wyświetlony przycisk Przesyłka produktu procesu nad elementem GridView zawierającym listę produktów dziesięć naraz.

GridView Listy możliwości sortowania i stronicowania produktów i ofert

Rysunek 5. Widok GridView Listy możliwości sortowania i stronicowania produktów i ofert (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 2. Tworzenie interfejsu wstawiania

Po zakończeniu interfejsu wyświetlania jesteśmy gotowi do utworzenia interfejsu wstawiania. Na potrzeby tego samouczka utwórzmy interfejs wstawiania, który monituje o jedną wartość dostawcy i kategorii, a następnie umożliwia użytkownikowi wprowadzanie maksymalnie pięciu nazw produktów i wartości cen jednostkowych. Dzięki temu interfejsowi użytkownik może dodać jeden do pięciu nowych produktów, które mają taką samą kategorię i dostawcę, ale mają unikatowe nazwy produktów i ceny.

Zacznij od przeciągnięcia panelu z przybornika na Projektant, umieszczając go pod istniejącym DisplayInterface Panelem. ID Ustaw właściwość tego nowo dodanego panelu na InsertingInterface i ustaw jej Visible właściwość na False. Dodamy kod, który ustawia InsertingInterface właściwość Panel Visible na True w kroku 3. Usuń również zaznaczenie wartości właściwości i Width paneliHeight.

Następnie musimy utworzyć interfejs wstawiania, który został pokazany z powrotem na rysunku 1. Ten interfejs można utworzyć za pomocą różnych technik HTML, ale użyjemy dość prostego: czterokolumna, siedmioosobowa tabela.

Uwaga

Podczas wprowadzania znaczników dla elementów HTML <table> preferuję korzystanie z widoku Źródło. Chociaż program Visual Studio ma narzędzia do dodawania <table> elementów za pośrednictwem Projektant, Projektant wydaje się zbyt skłonny do wstrzykiwania nieoznakowanych style ustawień do znaczników. Po utworzeniu <table> znaczników zwykle wracam do Projektant, aby dodać kontrolki sieci Web i ustawić ich właściwości. Podczas tworzenia tabel ze wstępnie określonymi kolumnami i wierszami preferuję używanie statycznego kodu HTML, a nie kontrolki Sieci Web tabel , ponieważ wszystkie kontrolki sieci Web umieszczone w kontrolce Tabela Web mogą być dostępne tylko przy użyciu FindControl("controlID") wzorca. Używam jednak kontrolek sieci Web tabel dla tabel o dynamicznym rozmiarze (tych, których wiersze lub kolumny są oparte na niektórych kryteriach bazy danych lub określonych przez użytkownika), ponieważ kontrolka tabela sieci Web może być konstruowana programowo.

Wprowadź następujące znaczniki w <asp:Panel> tagach InsertingInterface panelu:

<table class="DataWebControlStyle" cellspacing="0">
    <tr class="BatchInsertHeaderRow">
        <td class="BatchInsertLabel">Supplier:</td>
        <td></td>
        <td class="BatchInsertLabel">Category:</td>
        <td></td>
    </tr>
    <tr class="BatchInsertRow">
        <td class="BatchInsertLabel">Product:</td>
        <td></td>
        <td class="BatchInsertLabel">Price:</td>
        <td></td>
    </tr>
    <tr class="BatchInsertAlternatingRow">
        <td class="BatchInsertLabel">Product:</td>
        <td></td>
        <td class="BatchInsertLabel">Price:</td>
        <td></td>
    </tr>
    <tr class="BatchInsertRow">
        <td class="BatchInsertLabel">Product:</td>
        <td></td>
        <td class="BatchInsertLabel">Price:</td>
        <td></td>
    </tr>
    <tr class="BatchInsertAlternatingRow">
        <td class="BatchInsertLabel">Product:</td>
        <td></td>
        <td class="BatchInsertLabel">Price:</td>
        <td></td>
    </tr>
    <tr class="BatchInsertRow">
        <td class="BatchInsertLabel">Product:</td>
        <td></td>
        <td class="BatchInsertLabel">Price:</td>
        <td></td>
    </tr>
    <tr class="BatchInsertFooterRow">
        <td colspan="4">
        </td>
    </tr>
</table>

Ta <table> adiustacja nie zawiera jeszcze żadnych kontrolek sieci Web. Dodamy je chwilowo. Należy pamiętać, że każdy <tr> element zawiera określone ustawienie klasy CSS: BatchInsertHeaderRow dla wiersza nagłówka, w którym zostanie wybrana lista rozwijana dostawcy i kategorii; w wierszu stopki, w którym zostaną dodane BatchInsertFooterRow produkty z menu Wysyłka i Anuluj przyciski, oraz naprzemiennie BatchInsertRowBatchInsertAlternatingRow i wartości dla wierszy, które będą zawierać kontrolki Product i Unit Price TextBox. Utworzono odpowiednie klasy CSS w pliku w Styles.css celu nadania interfejsowi wstawiania wygląd podobny do kontrolek GridView i DetailsView używanych w tych samouczkach. Poniżej przedstawiono te klasy CSS.

/*** Styles for ~/BatchData/BatchInsert.aspx tutorial ***/
.BatchInsertLabel
{
    font-weight: bold;
    text-align: right;
}
.BatchInsertHeaderRow td
{
    color: White;
    background-color: #900;
    padding: 11px;
}
.BatchInsertFooterRow td
{
    text-align: center;
    padding-top: 5px;
}
.BatchInsertRow
{
}
.BatchInsertAlternatingRow
{
    background-color: #fcc;
}

Po wprowadzeniu tego znacznika wróć do widoku Projekt. Powinno to <table> być wyświetlane jako tabela czterokolumna, siedem wierszy w Projektant, jak pokazano na rysunku 6.

Interfejs wstawiania składa się z czterech kolumn, Seven-Row tabeli

Rysunek 6. Interfejs wstawiania składa się z czterech kolumn, Seven-Row tabeli (kliknij, aby wyświetlić obraz pełnowymiarowy)

Teraz możemy dodać kontrolki sieci Web do interfejsu wstawiania. Przeciągnij dwie listy rozwijane z przybornika do odpowiednich komórek w tabeli jedną dla dostawcy i jedną dla kategorii.

Ustaw właściwość dostawcy DropDownList ID na Suppliers i powiąż ją z nowym obiektem ObjectDataSource o nazwie SuppliersDataSource. Skonfiguruj nowe źródło ObjectDataSource, aby pobrać dane z SuppliersBLL metody klasy s GetSuppliers i ustawić listę rozwijaną kart UPDATE na wartość (Brak). Kliknij przycisk Zakończ, aby zakończyć kreatora.

Konfigurowanie obiektu ObjectDataSource do używania metody GetSuppliers klasy SuppliersBLL

Rysunek 7. Konfigurowanie obiektu ObjectDataSource do używania SuppliersBLL metody klasy GetSuppliers (kliknij, aby wyświetlić obraz pełnowymiarowy)

Aby lista Suppliers Rozwijana Lista rozwijana wyświetlała CompanyName pole danych i używać SupplierID pola danych jako wartości ListItem .

Wyświetl pole danych Nazwa_firmy i Użyj identyfikatora dostawcy jako wartość

Rysunek 8. Wyświetlanie CompanyName pola danych i użycie SupplierID jako wartości (kliknij, aby wyświetlić obraz pełnowymiarowy)

Nadaj drugiej liście DropDownList Categories nazwę i powiąż ją z nowym obiektem ObjectDataSource o nazwie CategoriesDataSource. Skonfiguruj obiekt CategoriesDataSource ObjectDataSource do użycia CategoriesBLL metody klasy s GetCategories . Ustaw listy rozwijane na kartach UPDATE i DELETE na wartość (Brak), a następnie kliknij przycisk Zakończ, aby ukończyć pracę kreatora. Na koniec lista rozwijana Lista rozwijana wyświetla CategoryName pole danych i użyj wartości CategoryID jako wartości.

Po dodaniu tych dwóch list rozwijanych i powiązanych z odpowiednio skonfigurowanymi obiektami ObjectDataSources ekran powinien wyglądać podobnie do rysunku 9.

Wiersz nagłówka zawiera teraz listy rozwijane dostawców i kategorii

Rysunek 9. Wiersz nagłówka zawiera Suppliers teraz listy rozwijane i Categories (kliknij, aby wyświetlić obraz pełnowymiarowy)

Teraz musimy utworzyć pola TextBoxes, aby zebrać nazwę i cenę dla każdego nowego produktu. Przeciągnij kontrolkę TextBox z przybornika na Projektant dla każdej z pięciu nazw produktów i wierszy cen. ID Ustaw właściwości pola TextBoxes na ProductName1, , UnitPrice2ProductName3UnitPrice1ProductName2, UnitPrice3i tak dalej.

Dodaj element CompareValidator po każdej cenie jednostkowej TextBoxes, ustawiając ControlToValidate właściwość na odpowiednią IDwartość . Operator Ustaw również właściwość na wartość , ValueToCompare na GreaterThanEqualwartość 0 i Type na Currencywartość . Te ustawienia instruują narzędzie CompareValidator, aby upewnić się, że cena, jeśli została wprowadzona, jest prawidłową wartością waluty, która jest większa lub równa zero. Text Ustaw właściwość na *, a ErrorMessage cena musi być większa lub równa zero. Ponadto pomiń wszystkie symbole waluty.

Uwaga

Interfejs wstawiania nie zawiera żadnych kontrolek RequiredFieldValidator, mimo że ProductName pole w Products tabeli bazy danych nie zezwala na NULL wartości. Dzieje się tak, ponieważ chcemy zezwolić użytkownikowi na wprowadzanie maksymalnie pięciu produktów. Jeśli na przykład użytkownik miał podać nazwę produktu i cenę jednostkową pierwszych trzech wierszy, pozostawiając ostatnie dwa wiersze puste, dodaliśmy tylko trzy nowe produkty do systemu. Ponieważ ProductName jest to jednak wymagane, musimy programowo sprawdzić, czy w przypadku wprowadzenia ceny jednostkowej podano odpowiednią wartość nazwy produktu. Zajmiemy się tym zaewidencjonem w kroku 4.

Podczas sprawdzania poprawności danych wejściowych użytkownika narzędzie CompareValidator zgłasza nieprawidłowe dane, jeśli wartość zawiera symbol waluty. Dodaj $ przed każdą ceną jednostkową TextBoxes, aby służyć jako wizualny sygnał, który nakazuje użytkownikowi pominięcie symbolu waluty podczas wprowadzania ceny.

Na koniec dodaj kontrolkę ValidationSummary w InsertingInterface panelu, ustaw jej ShowMessageBox właściwość na True i jej ShowSummary właściwość na False. W przypadku tych ustawień, jeśli użytkownik wprowadzi nieprawidłową wartość ceny jednostkowej, gwiazdka pojawi się obok kontrolek TextBox, a właściwość ValidationSummary wyświetli pole komunikatu po stronie klienta, które pokazuje wcześniej określony komunikat o błędzie.

Na tym etapie ekran powinien wyglądać podobnie do rysunku 10.

Interfejs wstawiania zawiera teraz pola tekstowe dla nazw produktów i cen

Rysunek 10. Interfejs wstawiania zawiera teraz pola tekstowe dla nazw produktów i cen (kliknij, aby wyświetlić obraz pełnowymiarowy)

Następnie musimy dodać przyciski Dodaj produkty z wysyłki i Anuluj do wiersza stopki. Przeciągnij dwa kontrolki Przycisk z przybornika do stopki interfejsu wstawiania, ustawiając właściwości Przyciski ID na AddProducts i CancelButton i Text właściwości, aby odpowiednio dodać produkty z wysyłki i anulowania. Ponadto ustaw właściwość s CausesValidation kontrolki CancelButton na false.

Na koniec musimy dodać kontrolkę Sieć Web Etykieta, która będzie wyświetlać komunikaty o stanie dla dwóch interfejsów. Na przykład gdy użytkownik pomyślnie doda nową przesyłkę produktów, chcemy wrócić do interfejsu wyświetlania i wyświetlić komunikat potwierdzający. Jeśli jednak użytkownik podaje cenę nowego produktu, ale pozostawia nazwę produktu, musimy wyświetlić komunikat ostrzegawczy, ponieważ ProductName pole jest wymagane. Ponieważ potrzebujemy tego komunikatu do wyświetlenia dla obu interfejsów, umieść go w górnej części strony poza panelami.

Przeciągnij kontrolkę Etykieta sieci Web z przybornika do góry strony w Projektant. ID Ustaw właściwość na StatusLabel, wyczyść Text właściwość i ustaw Visible dla właściwości i EnableViewState wartość False. Jak widzieliśmy w poprzednich samouczkach, ustawienie EnableViewState właściwości w celu False pozwala nam programowo zmienić wartości właściwości Etykieta i automatycznie przywrócić ich wartości domyślne w kolejnym poście zwrotnym. Upraszcza to kod wyświetlania komunikatu o stanie w odpowiedzi na akcję użytkownika, która znika po kolejnym poście zwrotnym. Na koniec ustaw właściwość kontrolki StatusLabelCssClass na Ostrzeżenie, która jest nazwą klasy CSS zdefiniowanej w tym, która wyświetla tekst w Styles.css dużej, kursywie, pogrubionej, czerwonej czcionki.

Rysunek 11 przedstawia Projektant programu Visual Studio po dodaniu i skonfigurowaniu etykiety.

Umieść kontrolkę StatusLabel nad kontrolkami dwóch paneli

Rysunek 11. Umieść kontrolkę StatusLabel nad kontrolkami Dwóch paneli (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 3. Przełączanie między interfejsami wyświetlania i wstawiania

W tym momencie ukończyliśmy znaczniki dla interfejsów wyświetlania i wstawiania, ale nadal pozostajemy z dwoma zadaniami:

  • Przełączanie między interfejsami wyświetlania i wstawiania
  • Dodawanie produktów do bazy danych

Obecnie interfejs wyświetlania jest widoczny, ale interfejs wstawiania jest ukryty. Dzieje się tak, ponieważ DisplayInterface właściwość Panel Visible jest ustawiona na True wartość (wartość domyślna), podczas gdy InsertingInterface właściwość Panel Visible jest ustawiona na Falsewartość . Aby przełączyć się między dwoma interfejsami, wystarczy przełączyć każdą wartość właściwości kontrolki Visible .

Chcemy przejść z interfejsu wyświetlania do interfejsu wstawiania po kliknięciu przycisku Przesyłka produktu procesu. W związku z tym utwórz procedurę obsługi zdarzeń dla tego zdarzenia przycisku Click , które zawiera następujący kod:

Protected Sub ProcessShipment_Click(sender As Object, e As EventArgs) _
    Handles ProcessShipment.Click
    DisplayInterface.Visible = False
    InsertingInterface.Visible = True
End Sub

Ten kod powoduje po prostu ukrycie DisplayInterface panelu i wyświetlenie InsertingInterface panelu.

Następnie utwórz programy obsługi zdarzeń dla kontrolek Dodaj produkty z wysyłki i Przycisku anulowania w interfejsie wstawiania. Po kliknięciu jednego z tych przycisków musimy wrócić do interfejsu wyświetlania. Utwórz Click programy obsługi zdarzeń dla obu kontrolek Przycisk, aby wywoływać ReturnToDisplayInterfacemetodę , którą dodamy chwilowo. Oprócz ukrywania InsertingInterface panelu i wyświetlania DisplayInterface panelu ReturnToDisplayInterface metoda musi zwrócić kontrolki sieci Web do stanu wstępnej edycji. Obejmuje to ustawienie właściwości DropDownLists SelectedIndex na wartość 0 i wyczyszczenie Text właściwości kontrolek TextBox.

Uwaga

Rozważ, co może się zdarzyć, jeśli nie przywróciliśmy kontrolek do stanu przed edycją przed powrotem do interfejsu wyświetlania. Użytkownik może kliknąć przycisk Przetwarzaj przesyłkę produktu, wprowadzić produkty z przesyłki, a następnie kliknąć pozycję Dodaj produkty z przesyłki. Spowoduje to dodanie produktów i zwrócenie użytkownika do interfejsu wyświetlania. W tym momencie użytkownik może chcieć dodać kolejną przesyłkę. Po kliknięciu przycisku Przetwarzaj przesyłkę produktu zostaną one zwrócone do interfejsu wstawiania, ale opcje Lista rozwijanaLista i wartości TextBox nadal będą wypełniane ich poprzednimi wartościami.

Protected Sub AddProducts_Click(sender As Object, e As EventArgs) _
    Handles AddProducts.Click
    ' TODO: Save the products
    ' Revert to the display interface
    ReturnToDisplayInterface()
End Sub
Protected Sub CancelButton_Click(sender As Object, e As EventArgs) _
    Handles CancelButton.Click
    ' Revert to the display interface
    ReturnToDisplayInterface()
End Sub
Const firstControlID As Integer = 1
Const lastControlID As Integer = 5
Private Sub ReturnToDisplayInterface()
    ' Reset the control values in the inserting interface
    Suppliers.SelectedIndex = 0
    Categories.SelectedIndex = 0
    For i As Integer = firstControlID To lastControlID
        CType(InsertingInterface.FindControl _
            ("ProductName" + i.ToString()), TextBox).Text = String.Empty
        CType(InsertingInterface.FindControl _
            ("UnitPrice" + i.ToString()), TextBox).Text = String.Empty
    Next
    DisplayInterface.Visible = True
    InsertingInterface.Visible = False
End Sub

Oba Click programy obsługi zdarzeń po prostu wywołają metodę ReturnToDisplayInterface , chociaż wrócimy do procedury obsługi zdarzeń Dodaj produkty z wysyłki Click w kroku 4 i dodamy kod, aby zapisać produkty. ReturnToDisplayInterface rozpoczyna się od zwrócenia listy rozwijanej Suppliers i Categories do ich pierwszych opcji. Dwie stałe firstControlID i lastControlID oznaczą wartości indeksu początkowego i końcowego kontrolki używane w nazewnictwie nazwy produktu i ceny jednostkowej TextBoxes w interfejsie wstawiania i są używane w granicach For pętli, która ustawia Text właściwości kontrolek TextBox z powrotem na pusty ciąg. Na koniec właściwości Panele Visible są resetowane, aby interfejs wstawiania był ukryty i wyświetlany interfejs wyświetlania.

Poświęć chwilę, aby przetestować tę stronę w przeglądarce. Podczas pierwszej wizyty na stronie powinien zostać wyświetlony interfejs wyświetlania, jak pokazano na rysunku 5. Kliknij przycisk Przetwarzaj przesyłkę produktu. Strona zostanie wycofana i powinna zostać wyświetlony interfejs wstawiania, jak pokazano na rysunku 12. Kliknięcie przycisków Dodaj produkty z wysyłki lub Anuluj powoduje powrót do interfejsu wyświetlania.

Uwaga

Podczas przeglądania interfejsu wstawiania poświęć chwilę, aby przetestować moduły CompareValidators w cenie jednostkowej TextBoxes. Po kliknięciu przycisku Dodaj produkty z przesyłki z nieprawidłowymi wartościami waluty lub cenami o wartości mniejszej niż zero powinna zostać wyświetlona ostrzeżenie po stronie klienta.

Interfejs wstawiania jest wyświetlany po kliknięciu przycisku Przesyłka produktu procesu

Rysunek 12. Interfejs wstawiania jest wyświetlany po kliknięciu przycisku Przesyłka produktu procesu (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 4. Dodawanie produktów

Wszystko, co pozostaje w tym samouczku, to zapisanie produktów w bazie danych w procedurze obsługi zdarzeń Dodaj produkty z przycisku Click wysyłki. Można to zrobić, tworząc i ProductsDataTable dodając ProductsRow wystąpienie dla każdej dostarczonej nazwy produktów. Po dodaniu tych ProductsRow elementów wykonamy wywołanie ProductsBLL metody klasy UpdateWithTransaction przekazującej ProductsDataTableelement . Pamiętaj, że metoda, która została utworzona z powrotem w samouczku Zawijanie UpdateWithTransactionmodyfikacji bazy danych w ramach transakcji , przekazuje ProductsDataTable metodę ProductsTableAdapterdo metody "s UpdateWithTransaction ". W tym miejscu jest uruchamiana transakcja ADO.NET, a obiekt TableAdapter wystawia instrukcję INSERT do bazy danych dla każdego dodanego ProductsRow w tabeli DataTable. Zakładając, że wszystkie produkty są dodawane bez błędu, transakcja zostanie zatwierdzona, w przeciwnym razie zostanie wycofana.

Kod obsługi zdarzeń Dodaj produkty z przycisku Click wysyłki również musi wykonać trochę sprawdzania błędów. Ponieważ nie ma elementów RequiredFieldValidator używanych w interfejsie wstawiania, użytkownik może wprowadzić cenę produktu, pomijając jego nazwę. Ponieważ nazwa produktu jest wymagana, jeśli taki warunek rozwija się, musimy powiadomić użytkownika i nie kontynuować wstawiania. Click Kompletny kod obsługi zdarzeń jest następujący:

Protected Sub AddProducts_Click(sender As Object, e As EventArgs) _
    Handles AddProducts.Click
    ' Make sure that the UnitPrice CompareValidators report valid data...
    If Not Page.IsValid Then Exit Sub
    ' Add new ProductsRows to a ProductsDataTable...
    Dim products As New Northwind.ProductsDataTable()
    For i As Integer = firstControlID To lastControlID
        ' Read in the values for the product name and unit price
        Dim productName As String = CType(InsertingInterface.FindControl _
            ("ProductName" + i.ToString()), TextBox).Text.Trim()
        Dim unitPrice As String = CType(InsertingInterface.FindControl _
            ("UnitPrice" + i.ToString()), TextBox).Text.Trim()
        ' Ensure that if unitPrice has a value, so does productName
        If unitPrice.Length > 0 AndAlso productName.Length = 0 Then
            ' Display a warning and exit this event handler
            StatusLabel.Text = "If you provide a unit price you must also 
                                include the name of the product."
            StatusLabel.Visible = True
            Exit Sub
        End If
        ' Only add the product if a product name value is provided
        If productName.Length > 0 Then
            ' Add a new ProductsRow to the ProductsDataTable
            Dim newProduct As Northwind.ProductsRow = products.NewProductsRow()
            ' Assign the values from the web page
            newProduct.ProductName = productName
            newProduct.SupplierID = Convert.ToInt32(Suppliers.SelectedValue)
            newProduct.CategoryID = Convert.ToInt32(Categories.SelectedValue)
            If unitPrice.Length > 0 Then
                newProduct.UnitPrice = Convert.ToDecimal(unitPrice)
            End If
            ' Add any "default" values
            newProduct.Discontinued = False
            newProduct.UnitsOnOrder = 0
            products.AddProductsRow(newProduct)
        End If
    Next
    ' If we reach here, see if there were any products added
    If products.Count > 0 Then
        ' Add the new products to the database using a transaction
        Dim productsAPI As New ProductsBLL()
        productsAPI.UpdateWithTransaction(products)
        ' Rebind the data to the grid so that the products just added are displayed
        ProductsGrid.DataBind()
        ' Display a confirmation (don't use the Warning CSS class, though)
        StatusLabel.CssClass = String.Empty
        StatusLabel.Text = String.Format( _
            "{0} products from supplier {1} have been " & _
            "added and filed under category {2}.", _
            products.Count, Suppliers.SelectedItem.Text, Categories.SelectedItem.Text)
        StatusLabel.Visible = True
        ' Revert to the display interface
        ReturnToDisplayInterface()
    Else
        ' No products supplied!
        StatusLabel.Text = 
            "No products were added. Please enter the " & _
            "product names and unit prices in the textboxes."
        StatusLabel.Visible = True
    End If
End Sub

Procedura obsługi zdarzeń rozpoczyna się od upewnienia się, że Page.IsValid właściwość zwraca wartość .True Jeśli zwróci Falsewartość , oznacza to, że co najmniej jeden element CompareValidator zgłasza nieprawidłowe dane. W takim przypadku nie chcemy próbować wstawić wprowadzonych produktów lub wystąpi wyjątek podczas próby przypisania wartości ceny jednostkowej wprowadzonej przez użytkownika do ProductsRowUnitPrice właściwości.

Następnie zostanie utworzone nowe ProductsDataTable wystąpienie (products). Pętla For służy do iteracji przez nazwę produktu i cenę jednostkową TextBoxes, a Text właściwości są odczytywane do zmiennych productName lokalnych i unitPrice. Jeśli użytkownik wprowadził wartość dla ceny jednostkowej, ale nie dla odpowiedniej nazwy produktu, zostanie wyświetlony komunikat Jeśli podasz cenę jednostkową, StatusLabel musisz również dołączyć nazwę produktu i program obsługi zdarzeń zostanie zakończona.

Jeśli podano nazwę produktu, zostanie utworzone nowe ProductsRow wystąpienie przy użyciu ProductsDataTable metody s NewProductsRow . Ta nowa ProductsRow właściwość wystąpienia ProductName jest ustawiona na bieżącą nazwę produktu TextBox, podczas gdy SupplierID właściwości i CategoryID są przypisane do SelectedValue właściwości list DropDownLists w nagłówku interfejsu wstawiania. Jeśli użytkownik wprowadził wartość dla ceny produktu, zostanie przypisany do ProductsRow właściwości wystąpienia UnitPrice . W przeciwnym razie właściwość pozostanie nieprzypisane, co spowoduje NULL , że wartość elementu UnitPrice w bazie danych zostanie przypisana. Discontinued Na koniec właściwości i UnitsOnOrder są przypisane odpowiednio do wartości False zakodowanych na kodzie i 0.

Po przypisaniu właściwości do ProductsRow wystąpienia zostanie ono dodane do obiektu ProductsDataTable.

Po zakończeniu For pętli sprawdzamy, czy zostały dodane jakiekolwiek produkty. Użytkownik może w końcu kliknąć pozycję Dodaj produkty z przesyłki przed wprowadzeniem nazw produktów lub cen. Jeśli w metodzie ProductsDataTablejest co najmniej jeden produkt , ProductsBLL wywoływana jest metoda klasy s UpdateWithTransaction . Następnie dane zostaną odzyskane do kontrolki ProductsGrid GridView, aby nowo dodane produkty pojawiły się w interfejsie wyświetlania. Element StatusLabel jest aktualizowany w celu wyświetlenia komunikatu potwierdzenia i ReturnToDisplayInterface wywołania, ukrywania interfejsu wstawiania i wyświetlania interfejsu wyświetlania.

Jeśli nie wprowadzono żadnych produktów, interfejs wstawiania pozostaje wyświetlany, ale komunikat Nie dodano żadnych produktów. Wprowadź nazwy produktów i ceny jednostkowe w polach tekstowych.

Na rysunku 13, 14 i 15 przedstawiono wstawiania i wyświetlania interfejsów w akcji. Na rysunku 13 użytkownik wprowadził wartość ceny jednostkowej bez odpowiedniej nazwy produktu. Rysunek 14 przedstawia interfejs wyświetlania po pomyślnym dodaniu trzech nowych produktów, podczas gdy rysunek 15 przedstawia dwa z nowo dodanych produktów w elemecie GridView (trzeci z nich znajduje się na poprzedniej stronie).

Nazwa produktu jest wymagana podczas wprowadzania ceny jednostkowej

Rysunek 13. Nazwa produktu jest wymagana podczas wprowadzania ceny jednostkowej (kliknij, aby wyświetlić obraz pełnowymiarowy)

Dodano trzy nowe veggies dla dostawcy Mayumi s

Rysunek 14. Dodano trzy nowe veggies dla dostawcy Mayumi s (kliknij, aby wyświetlić obraz pełnowymiarowy)

Nowe produkty można znaleźć na ostatniej stronie kontrolki GridView

Rysunek 15. Nowe produkty można znaleźć na ostatniej stronie widoku GridView (kliknij, aby wyświetlić obraz pełnowymiarowy)

Uwaga

Logika wstawiania wsadowego używana w tym samouczku opakowuje wstawki w zakresie transakcji. Aby to sprawdzić, celowo wprowadź błąd na poziomie bazy danych. Na przykład zamiast przypisywać nową ProductsRow właściwość wystąpienia CategoryID do wybranej wartości w liście RozwijanejList Categories , przypisz ją do wartości takiej jak i * 5. Oto i indeksator pętli i ma wartości z zakresu od 1 do 5. W związku z tym podczas dodawania co najmniej dwóch produktów w partii wstaw pierwszy produkt będzie miał prawidłową CategoryID wartość (5), ale kolejne produkty będą miały CategoryID wartości, które nie są zgodne z CategoryID wartościami w Categories tabeli. Efekt netto polega na tym, że podczas gdy pierwszy INSERT powiedzie się, kolejne zakończy się niepowodzeniem z naruszeniem ograniczenia klucza obcego. Ponieważ wstawianie wsadowe jest niepodzielne, pierwszy INSERT zostanie wycofany, zwracając bazę danych do stanu przed rozpoczęciem procesu wstawiania wsadowego.

Podsumowanie

W tym i poprzednich dwóch samouczkach utworzyliśmy interfejsy, które umożliwiają aktualizowanie, usuwanie i wstawianie partii danych, z których wszystkie korzystały z obsługi transakcji dodane do warstwy dostępu do danych w samouczku Zawijanie modyfikacji bazy danych w ramach transakcji . W przypadku niektórych scenariuszy takie interfejsy użytkownika przetwarzania wsadowego znacznie zwiększają wydajność użytkownika końcowego, zmniejszając liczbę kliknięć, po powrocie zwrotnym i przełączniki kontekstowe klawiatury do myszy, zachowując jednocześnie integralność danych bazowych.

W tym samouczku przedstawiono pracę z danymi wsadowymi. W następnym zestawie samouczków przedstawiono różne zaawansowane scenariusze warstwy dostępu do danych, w tym przy użyciu procedur składowanych w metodach tableAdapter, konfigurowania ustawień połączenia i poziomu poleceń w dal, szyfrowania parametrów połączenia i nie tylko!

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 sprawdzona przez wielu pomocnych recenzentów. Recenzenci w tym samouczku byli Hilton Giesenow i S ren Jacob Lauritsen. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi wiersz pod adresem mitchell@4GuysFromRolla.com.