Delen via


Batch toevoegen (C#)

door Scott Mitchell

PDF downloaden

Meer informatie over het invoegen van meerdere databaserecords in één bewerking. In de gebruikersinterfacelaag breiden we GridView uit zodat de gebruiker meerdere nieuwe records kan invoeren. In de Data Access-laag verpakken we de meerdere invoegbewerkingen binnen een transactie om ervoor te zorgen dat alle invoegingen slagen of dat alle invoegingen worden teruggedraaid.

Introductie

In de zelfstudie Batch-updates hebben we gekeken naar het aanpassen van het GridView-besturingselement om een interface weer te geven waarin meerdere records kunnen worden bewerkt. De gebruiker die de pagina bezoekt, kan een reeks wijzigingen aanbrengen en vervolgens met één klik een batch-update uitvoeren. In situaties waarin gebruikers veel records in één stap bijwerken, kan een dergelijke interface talloze muisklikken en wisselopties voor toetsenbord-naar-muis opslaan in vergelijking met de standaardbewerkingsfuncties per rij die voor het eerst zijn verkend in de zelfstudie Gegevens invoegen, bijwerken en verwijderen .

Dit concept kan ook worden toegepast bij het toevoegen van records. Stel dat we hier bij Northwind Traders vaak zendingen ontvangen van leveranciers die een aantal producten voor een bepaalde categorie bevatten. Als voorbeeld kunnen we een zending ontvangen van zes verschillende thee- en koffieproducten van Tokyo Traders. Als een gebruiker de zes producten één voor één invoert via een DetailView-besturingselement, moeten ze steeds dezelfde waarden kiezen: ze moeten dezelfde categorie kiezen (Dranken), dezelfde leverancier (Tokio Traders), dezelfde stopgezette waarde (Onwaar) en dezelfde eenheden op orderwaarde (0). Deze terugkerende gegevensinvoer is niet alleen tijdrovend, maar is gevoelig voor fouten.

Met weinig werk kunnen we een batch-invoeginterface maken waarmee de gebruiker eenmaal de leverancier en categorie kan kiezen, een reeks productnamen en eenheidsprijzen kan invoeren en vervolgens op een knop klikt om de nieuwe producten toe te voegen aan de database (zie afbeelding 1). Wanneer elk product wordt toegevoegd, worden de ProductName en UnitPrice gegevensvelden toegewezen aan de waarden die zijn ingevoerd in de tekstvakken, terwijl de CategoryID en SupplierID waarden worden toegewezen aan de waarden uit de vervolgkeuzelijsten bovenaan het formulier. De Discontinued waarden en UnitsOnOrder waarden worden ingesteld op respectievelijk de in code vastgelegde waarden van false respectievelijk 0.

De interface voor batchinvoeging

Afbeelding 1: De interface voor batchinvoeging (klik om de afbeelding in volledige grootte weer te geven)

In deze zelfstudie maken we een pagina waarmee de interface voor batchinvoeging in afbeelding 1 wordt geïmplementeerd. Net als bij de vorige twee zelfstudies verpakken we de toevoegingen binnen de omvang van een transactie om atomiciteit te garanderen. Laten we beginnen!

Stap 1: de weergave-interface maken

Deze zelfstudie bestaat uit één pagina die is onderverdeeld in twee regio's: een weergaveregio en een invoegregio. De weergave-interface, die we in deze stap gaan maken, toont de producten in een GridView en bevat een knop met het opschrift Verwerk productverzending. Wanneer op deze knop wordt geklikt, wordt de weergave-interface vervangen door de invoeginterface, die wordt weergegeven in afbeelding 1. De interface keert terug nadat op de knoppen 'Producten toevoegen aan verzending' of 'Annuleren' is geklikt. We maken de invoeginterface in stap 2.

Bij het maken van een pagina met twee interfaces, waarvan er slechts één tegelijk zichtbaar is, wordt elke interface meestal in een configuratiescherm geplaatst, dat fungeert als een container voor andere besturingselementen. Daarom zal onze pagina twee paneelbesturingselementen bevatten: een voor elke interface.

Open eerst de BatchInsert.aspx pagina in de BatchData map en sleep een paneel van de werkset naar de ontwerpfunctie (zie afbeelding 2). Stel de eigenschap van Panel ID in op DisplayInterface. Wanneer u het deelvenster toevoegt aan de ontwerper, worden de eigenschappen Height en Width ervan ingesteld op respectievelijk 50 pixels en 125 pixels. Wis deze eigenschapswaarden uit het venster Eigenschappen.

Sleep een paneel van de gereedschapskist naar de ontwerper

Afbeelding 2: Sleep een paneel van de werkset naar de ontwerpfunctie (klik om de afbeelding volledig weer te geven)

Sleep vervolgens een Button- en GridView-besturingselement naar het deelvenster. Stel de eigenschap van de Knop in ID op ProcessShipment en de eigenschap Text op Productverzending verwerken. Stel de eigenschap van de GridView in op IDProductsGrid en koppel deze via de smart tag aan een nieuwe ObjectDataSource genaamd ProductsDataSource. Configureer de ObjectDataSource om de gegevens op te halen uit de ProductsBLL klasse en de GetProducts methode. Omdat deze GridView alleen wordt gebruikt om gegevens weer te geven, stelt u de vervolgkeuzelijsten in de tabbladen UPDATE, INSERT en DELETE in op (Geen). Klik op Voltooien om de wizard Gegevensbron configureren te voltooien.

De gegevens weergeven die zijn geretourneerd uit de methode ProductsBLL-klasse GetProducts

Afbeelding 3: De gegevens weergeven die zijn geretourneerd uit de methode van ProductsBLL klasse GetProducts (klik om de afbeelding op volledige grootte weer te geven)

Stel de Drop-Down-lijsten in de tabbladen UPDATE, INSERT en DELETE in op (Geen)

Afbeelding 4: Stel de Drop-Down lijsten in de tabbladen UPDATE, INSERT en DELETE in op (Geen) (Klik om de volledige afbeelding weer te geven)

Nadat de wizard ObjectDataSource is voltooid, voegt Visual Studio BoundFields en een CheckBoxField toe voor de productgegevensvelden. Verwijder alle velden behalve de ProductName, CategoryName, SupplierNameen UnitPriceDiscontinued de velden. Voel je vrij om eventuele esthetische aanpassingen te maken. Ik heb besloten het UnitPrice veld op te maken als valutawaarde, de volgorde van de velden te wijzigen en verschillende veldenwaarden HeaderText te hernoemen. Configureer ook de GridView om ondersteuning voor pagina's en sortering toe te voegen door de selectievakjes 'Pagina's inschakelen' en 'Sorteren inschakelen' in de smart tag van de GridView te controleren.

Nadat u de besturingselementen Panel, Button, GridView en ObjectDataSource hebt toegevoegd en de velden van GridView hebt aangepast, moet de declaratieve markering van uw pagina er ongeveer als volgt uitzien:

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

Houd er rekening mee dat de markeringen voor de knop en GridView worden weergegeven binnen de openings- en slottags <asp:Panel> . Omdat deze besturingselementen zich in het DisplayInterface deelvenster bevinden, kunnen we ze verbergen door de eigenschap Panel Visible in te stellen op false. Stap 3 onderzoekt het programmatisch wijzigen van de eigenschap van Panel Visible als reactie op het klikken op een knop om één interface weer te geven terwijl de andere wordt verborgen.

Neem even de tijd om onze voortgang via een browser te bekijken. Zoals te zien is in afbeelding 5, zou u een knop 'Productverzending verwerken' moeten zien boven een GridView met de producten tien per keer.

De GridView toont de producten en biedt mogelijkheden voor sorteren en paginering

Afbeelding 5: De GridView bevat de producten en biedt sorteer- en pagingsmogelijkheden (klik hier om de volledige afbeelding weer te geven)

Stap 2: de interface voor invoegen maken

Nu de weergave-interface is voltooid, zijn we klaar om de invoeginterface te maken. Voor deze zelfstudie gaan we een invoeginterface maken waarmee wordt gevraagd om één leverancier en categoriewaarde. Vervolgens kan de gebruiker maximaal vijf productnamen en prijswaarden per eenheid invoeren. Met deze interface kan de gebruiker één tot vijf nieuwe producten toevoegen die allemaal dezelfde categorie en leverancier delen, maar unieke productnamen en prijzen hebben.

Sleep eerst een Paneel van de werkset naar de ontwerper en plaats het onder het bestaande DisplayInterface Paneel. Stel de ID-eigenschap van dit zojuist toegevoegde deelvenster in op InsertingInterface en stel de Visible-eigenschap in op false. In stap 3 zullen we code toevoegen die de eigenschap InsertingInterface van het Visible paneel instelt op true. Wis ook de eigenschapswaarden van paneel Height en Width.

Vervolgens moeten we de invoeginterface maken die in afbeelding 1 is weergegeven. Deze interface kan worden gemaakt via verschillende HTML-technieken, maar we gebruiken een vrij eenvoudige: een tabel met vier kolommen, zeven rijen.

Opmerking

Bij het invoeren van markeringen voor HTML-elementen <table> gebruik ik liever de bronweergave. Hoewel Visual Studio wel hulpprogramma's heeft voor het toevoegen van <table> elementen via de ontwerpfunctie, lijkt de ontwerper maar al te graag ongevraagde style-instellingen in de opmaak te injecteren. Zodra ik de <table> markeringen heb gemaakt, ga ik meestal terug naar de ontwerpfunctie om de webbesturingselementen toe te voegen en hun eigenschappen in te stellen. Bij het maken van tabellen met vooraf bepaalde kolommen en rijen geef ik de voorkeur aan het gebruik van statische HTML in plaats van het besturingselement Tabelweb , omdat webbesturingselementen die in een tabelwebbesturingselement worden geplaatst, alleen toegankelijk zijn met behulp van het FindControl("controlID") patroon. Ik gebruik echter tabelwebbesturingselementen voor tabellen met een dynamisch formaat (tabellen waarvan rijen of kolommen zijn gebaseerd op bepaalde database- of door de gebruiker opgegeven criteria), omdat het besturingselement Tabelweb programmatisch kan worden samengesteld.

Voer de volgende markeringen in de <asp:Panel> tags van het InsertingInterface deelvenster in:

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

Deze <table> markering bevat nog geen webbesturingselementen, we zullen die binnenkort toevoegen. Houd er rekening mee dat elk <tr> element een bepaalde CSS-klasse-instelling bevat: BatchInsertHeaderRow voor de koprij waar de leverancier- en categorie-dropdownlijsten komen; BatchInsertFooterRow voor de voettekstrij waar de knoppen Producten toevoegen uit zending en Annuleren worden gebruikt; en afwisselende BatchInsertRow en BatchInsertAlternatingRow waarden voor de rijen die de invoervelden voor product- en eenheidsprijzen bevatten. Ik heb overeenkomstige CSS-klassen in het Styles.css bestand gemaakt om de invoeginterface een uiterlijk te geven dat lijkt op de GridView- en DetailsView-besturingselementen die we in deze zelfstudies hebben gebruikt. Deze CSS-klassen worden hieronder weergegeven.

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

Als deze markering is ingevoerd, gaat u terug naar de ontwerpweergave. Dit <table> moet worden weergegeven als een tabel met vier kolommen, zeven rijen in de ontwerpfunctie, zoals in afbeelding 6 wordt geïllustreerd.

De invoeginterface bestaat uit een tabel met vier kolommen Seven-Row

Afbeelding 6: De invoeginterface bestaat uit een vierkolommen Seven-Row tabel (klik om de afbeelding op volledige grootte weer te geven)

We zijn nu klaar om de webbesturingselementen toe te voegen aan de invoeginterface. Sleep twee vervolgkeuzelijsten uit de werkset naar de juiste cellen in de tabel één voor de leverancier en één voor de categorie.

Stel de eigenschap ID van de leverancier DropDownList in op Suppliers en bind deze aan een nieuwe ObjectDataSource genaamd SuppliersDataSource. Configureer de nieuwe ObjectDataSource om zijn gegevens op te halen uit de SuppliersBLL klasse met de GetSuppliers methode en stel de vervolgkeuzelijst van de UPDATE-tab in op (Geen). Klik op Voltooien om de wizard te voltooien.

De ObjectDataSource configureren voor het gebruik van de methode SuppliersBLL-klasse GetSuppliers

Afbeelding 7: Configureer de ObjectDataSource om de SuppliersBLL klasse te gebruiken via de GetSuppliers methode (klik om de afbeelding op volledige grootte weer te geven)

Laat de Suppliers DropDownList het CompanyName gegevensveld weergeven en het SupplierID gegevensveld gebruiken als ListItem waarden.

Het veld CompanyName-gegevens weergeven en Leverancier-id gebruiken als de waarde

Afbeelding 8: Het CompanyName gegevensveld weergeven en gebruiken SupplierID als de waarde (klik om de afbeelding op volledige grootte weer te geven)

Geef de tweede DropDownList Categories een naam en bind deze aan een nieuwe ObjectDataSource met de naam CategoriesDataSource. Configureer de CategoriesDataSource ObjectDataSource om de methode van de CategoriesBLL klasse GetCategories te gebruiken. Stel de vervolgkeuzelijsten in de tabbladen UPDATE en DELETE in op (Geen) en klik op Voltooien om de wizard af te ronden. Laat tot slot de vervolgkeuzelijst het CategoryName gegevensveld weergeven en de CategoryID waarde gebruiken.

Nadat deze twee DropDownLists zijn toegevoegd en gebonden aan de juiste geconfigureerde ObjectDataSources, moet uw scherm er ongeveer uitzien als afbeelding 9.

De koprij bevat nu de vervolgkeuzelijsten voor leveranciers en categorieën

Afbeelding 9: De veldnamenrij bevat nu de Suppliers en Categories DropDownLists (klik om de volledige afbeelding weer te geven)

We moeten nu de tekstvakken maken om de naam en prijs voor elk nieuw product te verzamelen. Sleep een besturingselement Tekstvak van de Werkbalk naar de ontwerpfunctie voor elk van de vijf productnamen en prijsrijen. Stel de ID eigenschappen van de tekstvakken in op ProductName1, UnitPrice1, ProductName2, UnitPrice2, ProductName3, UnitPrice3, enzovoort.

Voeg een CompareValidator toe na elk van de textvakken voor de eenheidsprijs en stel de ControlToValidate eigenschap in op de juiste ID. Stel de Operator eigenschap ook in op GreaterThanEqual, ValueToCompare op 0 en Type op Currency. Met deze instellingen wordt de CompareValidator geïnstrueerd om ervoor te zorgen dat de prijs, indien ingevoerd, een geldige valutawaarde is die groter is dan of gelijk is aan nul. Stel de Text eigenschap in op *en ErrorMessage op De prijs moet groter dan of gelijk zijn aan nul. Laat ook valutasymbolen weg.

Opmerking

De invoeginterface bevat geen RequiredFieldValidator-besturingselementen, ook al zijn in het ProductName veld in de Products databasetabel geen waarden toegestaan NULL . Dit komt doordat we de gebruiker maximaal vijf producten willen laten invoeren. Als de gebruiker bijvoorbeeld de productnaam en eenheidsprijs voor de eerste drie rijen opgeeft en de laatste twee rijen leeg laat, voegen we gewoon drie nieuwe producten toe aan het systeem. Aangezien ProductName dit echter vereist is, moeten we programmatisch controleren om ervoor te zorgen dat als een eenheidsprijs wordt ingevoerd dat een overeenkomstige productnaamwaarde wordt opgegeven. We gaan deze controle in stap 4 aanpakken.

Bij het valideren van de invoer van de gebruiker rapporteert de CompareValidator ongeldige gegevens als de waarde een valutasymbool bevat. Voeg een $ toe vóór elk van de tekstvakken voor de eenheidsprijs om te fungeren als een visuele aanwijzing waarmee de gebruiker het valutasymbool weglaat bij het invoeren van de prijs.

Voeg ten slotte een ValidationSummary-besturingselement toe aan het InsertingInterface-paneel, waarbij u de eigenschap ShowMessageBox instelt op true en de eigenschap ShowSummary instelt op false. Als de gebruiker een ongeldige eenheidsprijswaarde invoert, wordt er met deze instellingen een sterretje weergegeven naast de betreffende tekstvakbesturingselementen en wordt in de validatiesamenvatting een messagebox aan de klantzijde weergegeven met het foutbericht dat we eerder hebben opgegeven.

Op dit moment moet uw scherm er ongeveer uitzien als afbeelding 10.

De invoeginterface bevat nu tekstvakken voor de productnamen en prijzen

Afbeelding 10: De invoeginterface bevat nu tekstvakken voor de productnamen en -prijzen (klik om de volledige afbeelding weer te geven)

Vervolgens moeten we de knoppen 'Producten toevoegen uit verzending' en 'Annuleren' aan de voettekstrij toevoegen. Sleep twee knop-elementen uit de Gereedschapskist naar de voettekst van de invoeginterface en stel de eigenschappen van de knoppen in op ID, AddProducts voor het toevoegen van producten vanuit de verzending, en CancelButton, Text voor annuleren. Stel daarnaast de eigenschap van CancelButton control s CausesValidation in op false.

Ten slotte moeten we een labelweb besturingselement toevoegen waarmee statusberichten voor de twee interfaces worden weergegeven. Wanneer een gebruiker bijvoorbeeld een nieuwe verzending van producten toevoegt, willen we terugkeren naar de weergave-interface en een bevestigingsbericht weergeven. Als de gebruiker echter een prijs voor een nieuw product biedt, maar de productnaam verlaat, moeten we een waarschuwingsbericht weergeven omdat het ProductName veld is vereist. Omdat we dit bericht nodig hebben om voor beide interfaces weer te geven, plaatst u het boven aan de pagina buiten de panelen.

Sleep een Label Webbesturingselement van de Werkset naar de bovenkant van de pagina in de ontwerper. Stel de ID eigenschap in op StatusLabel, wis de Text eigenschap en stel de Visible eigenschappen EnableViewState in op false. Zoals we in de vorige zelfstudies hebben gezien, kunt u de EnableViewState eigenschap false zodanig instellen dat we de eigenschapswaarden van Label programmatisch kunnen wijzigen en ervoor zorgen dat ze automatisch teruggaan naar de standaardwaarden voor de volgende postback. Dit vereenvoudigt de code voor het weergeven van een statusbericht als reactie op een bepaalde gebruikersactie die verdwijnt op de volgende postback. Stel ten slotte de eigenschap van het StatusLabel besturingselement CssClass in op Waarschuwing, wat de naam is van een CSS-klasse die is gedefinieerd in Styles.css, die tekst weergeeft in een groot, cursief, vet, rood lettertype.

In afbeelding 11 ziet u de Visual Studio Designer nadat het label is toegevoegd en geconfigureerd.

Plaats het besturingselement StatusLabel boven de twee paneelbesturingselementen

Afbeelding 11: Plaats het StatusLabel besturingselement boven de twee paneelbesturingen (klik om de afbeelding in volledige grootte te bekijken)

Stap 3: Schakelen tussen de weergaveinterface en het invoegen van interfaces

Op dit moment hebben we de opmaak voor onze weergave- en invoeginterfaces voltooid, maar we blijven nog steeds achter met twee taken:

  • Schakelen tussen de weergave en het invoegen van interfaces
  • De producten in de zending toevoegen aan de database

Momenteel is de weergave-interface zichtbaar, maar de invoeginterface is verborgen. Dit komt doordat de DisplayInterface eigenschap Panel Visible is ingesteld op true (de standaardwaarde), terwijl de InsertingInterface eigenschap Panel Visible is ingesteld op false. Om tussen de twee interfaces te schakelen, hoeven we alleen de eigenschapswaarde van Visible van elk besturingselement te wisselen.

We willen van de weergave-interface naar de invoeginterface gaan wanneer op de knop Productverzending proces wordt geklikt. Maak daarom een eventhandler voor deze knop Click-gebeurtenis die de volgende code bevat:

protected void ProcessShipment_Click(object sender, EventArgs e)
{
    DisplayInterface.Visible = false;
    InsertingInterface.Visible = true;
}

Met deze code wordt het DisplayInterface deelvenster verborgen en wordt het InsertingInterface deelvenster weergegeven.

Maak vervolgens gebeurtenis-handlers voor de besturingselementen Producten toevoegen van verzending en Knop Annuleren in de invoeginterface. Wanneer op een van deze knoppen wordt geklikt, moeten we teruggaan naar de weergave-interface. Maak Click gebeurtenis-handlers voor beide knopbesturingselementen, zodat ze ReturnToDisplayInterface, een methode die we binnenkort toevoegen, aanroepen. Naast het verbergen van het InsertingInterface paneel en het weergeven van het DisplayInterface paneel, moet de ReturnToDisplayInterface methode de webbesturingselementen terugbrengen naar hun oorspronkelijke staat. Dit omvat het instellen van de SelectedIndex eigenschappen van de DropDownLists op 0 en het wissen van de Text eigenschappen van de TextBox-besturingselementen.

Opmerking

Bedenk wat er kan gebeuren als we de besturingselementen niet hebben geretourneerd naar de status voorafgaand aan bewerking voordat we terugkeren naar de weergave-interface. Een gebruiker kan op de knop Productverzending verwerken klikken, de producten van de zending invoeren en vervolgens op Producten uit verzending toevoegen klikken. Hiermee worden de producten toegevoegd en wordt de gebruiker geretourneerd aan de weergave-interface. Op dit moment wil de gebruiker mogelijk een andere zending toevoegen. Wanneer u op de knop Productverzending proces klikt, keert u terug naar de invoeginterface, maar de selecties in de vervolgkeuzelijst en tekstvakwaarden worden nog steeds gevuld met de vorige waarden.

protected void AddProducts_Click(object sender, EventArgs e)
{
    // TODO: Save the products
    // Revert to the display interface
    ReturnToDisplayInterface();
}
protected void CancelButton_Click(object sender, EventArgs e)
{
    // Revert to the display interface
    ReturnToDisplayInterface();
}
const int firstControlID = 1;
const int lastControlID = 5;
private void ReturnToDisplayInterface()
{
    // Reset the control values in the inserting interface
    Suppliers.SelectedIndex = 0;
    Categories.SelectedIndex = 0;
    for (int i = firstControlID; i <= lastControlID; i++)
    {
        ((TextBox)InsertingInterface.FindControl("ProductName" + i.ToString())).Text =
            string.Empty;
        ((TextBox)InsertingInterface.FindControl("UnitPrice" + i.ToString())).Text = 
            string.Empty;
    }
    DisplayInterface.Visible = true;
    InsertingInterface.Visible = false;
}

Beide Click gebeurtenishandlers roepen de ReturnToDisplayInterface methode aan, hoewel wij in stap 4 terugkeren naar de gebeurtenishandler Producten van Verzending toevoegen Click en code toevoegen om de producten op te slaan. ReturnToDisplayInterface begint met het retourneren van de Suppliers en Categories DropDownLists naar de eerste opties. De twee constanten firstControlID en lastControlID markeren de begin- en eindbesturingsindexwaarden die worden gebruikt bij het benoemen van de productnaam en prijs per eenheid TextBox in de invoeginterface en worden gebruikt in de grenzen van de for lus, die ervoor zorgt dat de Text eigenschappen van de TextBox-besturingselementen terugkeren naar een lege tekenreeks. Ten slotte worden de eigenschappen Panels Visible opnieuw ingesteld, zodat de invoeginterface verborgen is en de weergave-interface wordt weergegeven.

Neem even de tijd om deze pagina in een browser te testen. Wanneer u de pagina voor het eerst bezoekt, ziet u de weergave-interface zoals is weergegeven in afbeelding 5. Klik op de knop Productverzending verwerken. De pagina wordt terug geplaatst en u ziet nu de invoeginterface, zoals weergegeven in afbeelding 12. Als u op de knoppen Producten toevoegen van verzending of Annuleren klikt, gaat u terug naar de weergave-interface.

Opmerking

Neem even de tijd om de CompareValidators op de tekstvakken voor eenheidsprijzen te testen terwijl u de invoeginterface bekijkt. U ziet een berichtvakwaarschuwing aan de clientzijde wanneer u op de knop Producten toevoegen uit verzending klikt met ongeldige valutawaarden of prijzen met een waarde kleiner dan nul.

De invoeginterface wordt weergegeven nadat u op de knop Productverzending proces hebt geklikt

Afbeelding 12: De invoeginterface wordt weergegeven nadat u op de knop Productverzending proces hebt geklikt (klik om de volledige afbeelding weer te geven)

Stap 4: de producten toevoegen

Alles wat overblijft voor deze zelfstudie is om de producten op te slaan in de database in de gebeurtenis-handler van de knop 'Producten toevoegen van verzending' Click. Dit kan worden bereikt door een ProductsDataTable te maken en een ProductsRow instantie toe te voegen voor elk van de opgegeven productnamen. Zodra deze ProductsRow s zijn toegevoegd, zullen we een aanroep doen naar de ProductsBLL methode van de UpdateWithTransaction klasse en de ProductsDataTable doorgeven. Zoals u zich herinnert, geeft de UpdateWithTransaction methode, die werd gemaakt in de tutorial Wrapping Database Modifications binnen een transactie, de ProductsDataTable door aan de ProductsTableAdapters UpdateWithTransaction methode. Van daaruit wordt een ADO.NET transactie gestart en geeft de TableAdapter een INSERT instructie uit aan de database voor elke vermelding die in de DataTable is toegevoegd ProductsRow . Ervan uitgaande dat alle producten zonder fouten worden toegevoegd, wordt de transactie doorgevoerd, anders wordt de transactie teruggedraaid.

De code voor de gebeurtenisverwerker van de knop "Producten Toevoegen vanuit Zending" moet Click ook een beetje foutcontrole uitvoeren. Omdat er geen RequiredFieldValidators worden gebruikt in de invoeginterface, kan een gebruiker een prijs voor een product invoeren terwijl de naam weglaat. Omdat de naam van het product vereist is, moeten we de gebruiker waarschuwen als een dergelijke voorwaarde zich ontvouwt en niet verdergaan met de invoegingen. De volledige Click code van de gebeurtenis-handler volgt:

protected void AddProducts_Click(object sender, EventArgs e)
{
    // Make sure that the UnitPrice CompareValidators report valid data...
    if (!Page.IsValid)
        return;
    // Add new ProductsRows to a ProductsDataTable...
    Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
    for (int i = firstControlID; i <= lastControlID; i++)
    {
        // Read in the values for the product name and unit price
        string productName = ((TextBox)InsertingInterface.FindControl
            ("ProductName" + i.ToString())).Text.Trim();
        string unitPrice = ((TextBox)InsertingInterface.FindControl
            ("UnitPrice" + i.ToString())).Text.Trim();
        // Ensure that if unitPrice has a value, so does productName
        if (unitPrice.Length > 0 && productName.Length == 0)
        {
            // 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;
            return;
        }
        // Only add the product if a product name value is provided
        if (productName.Length > 0)
        {
            // Add a new ProductsRow to the ProductsDataTable
            Northwind.ProductsRow newProduct = 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)
                newProduct.UnitPrice = Convert.ToDecimal(unitPrice);
            // Add any "default" values
            newProduct.Discontinued = false;
            newProduct.UnitsOnOrder = 0;
            products.AddProductsRow(newProduct);
        }
    }
    // If we reach here, see if there were any products added
    if (products.Count > 0)
    {
        // Add the new products to the database using a transaction
        ProductsBLL productsAPI = 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;
    }
}

De gebeurtenis-handler begint door ervoor te zorgen dat de Page.IsValid eigenschap een waarde retourneert van true. Als deze retourneertfalse, betekent dit dat een of meer van de CompareValidators ongeldige gegevens rapporteren. In dat geval willen we niet proberen de ingevoerde producten in te voegen of eindigen we met een uitzondering bij het toewijzen van de door de gebruiker ingevoerde eenheidsprijswaarde aan de ProductsRow eigenschap.UnitPrice

Vervolgens wordt er een nieuw ProductsDataTable exemplaar gemaakt (products). Een for lus wordt gebruikt om de tekstvakken voor productnaam en eenheidsprijs te doorlopen, en de Text eigenschappen worden gelezen in de lokale variabelen productName en unitPrice. Als de gebruiker een waarde voor de eenheidsprijs heeft ingevoerd, maar niet voor de bijbehorende productnaam, StatusLabel verschijnt het bericht dat als u een eenheidsprijs opgeeft, u ook de naam van het product moet invoeren, en dan wordt de gebeurtenis-handler afgesloten.

Als er een productnaam is opgegeven, wordt er een nieuw ProductsRow exemplaar gemaakt met behulp van de ProductsDataTable methode s NewProductsRow . Deze eigenschap van het nieuwe ProductsRow-exemplaarProductName wordt ingesteld op het tekstvak voor de huidige productnaam, terwijl de SupplierID en CategoryID eigenschappen worden toegewezen aan de SelectedValue eigenschappen van de DropDownLists in de kop van de invoeginterface. Als de gebruiker een waarde voor de prijs van het product heeft ingevoerd, wordt deze toegewezen aan de ProductsRow eigenschap van de UnitPrice instantie; anders blijft de eigenschap niet toegewezen, wat zal resulteren in een NULL waarde voor UnitPrice in de database. Ten slotte worden de Discontinued en UnitsOnOrder eigenschappen toegewezen aan respectievelijk de vastgelegde waarden false en 0.

Nadat de eigenschappen zijn toegewezen aan het ProductsRow exemplaar, wordt deze toegevoegd aan de ProductsDataTable.

Na voltooiing van de for lus controleren we of er producten zijn toegevoegd. De gebruiker kan tenslotte op producten van verzending toevoegen hebben geklikt voordat hij productnamen of prijzen invoert. Als er ten minste één product in ProductsDataTable is, wordt de ProductsBLL klasse's UpdateWithTransaction methode aangeroepen. Vervolgens worden de gegevens teruggestroomd naar de ProductsGrid GridView, zodat de zojuist toegevoegde producten worden weergegeven in de weergave-interface. Het StatusLabel bericht wordt bijgewerkt om een bevestigingsbericht weer te geven en het ReturnToDisplayInterface wordt aangeroepen, waarbij de invoeginterface wordt verborgen en de weergave-interface wordt weergegeven.

Als er geen producten zijn ingevoerd, blijft de invoeginterface zichtbaar, maar wordt het bericht Geen producten toegevoegd weergegeven. Voer de productnamen en eenheidsprijzen in de tekstvakken in.

In afbeelding 13, 14 en 15 worden de invoeg- en weergaveinterfaces in actie weergegeven. In afbeelding 13 heeft de gebruiker een prijswaarde per eenheid ingevoerd zonder een bijbehorende productnaam. In afbeelding 14 ziet u de weergaveinterface nadat drie nieuwe producten zijn toegevoegd, terwijl in afbeelding 15 twee van de nieuw toegevoegde producten in GridView worden weergegeven (de derde is op de vorige pagina).

Een productnaam is vereist bij het invoeren van een eenheidsprijs

Afbeelding 13: Een productnaam is vereist bij het invoeren van een eenheidsprijs (klik hier om de volledige afbeelding weer te geven)

Er zijn drie nieuwe veggies toegevoegd voor de leverancier Mayumi s

Afbeelding 14: Er zijn drie nieuwe veggies toegevoegd voor de leverancier Mayumi 's (klik om de afbeelding op volledige grootte weer te geven)

De nieuwe producten zijn te vinden op de laatste pagina van de GridView

Afbeelding 15: De nieuwe producten zijn te vinden op de laatste pagina van de GridView (klik hier om de volledige afbeelding weer te geven)

Opmerking

De batch-invoeglogica die in deze tutorial wordt gebruikt, plaatst de invoegingen binnen de scope van de transactie. Om dit te controleren, introduceert u doelbewust een fout op databaseniveau. Wijs bijvoorbeeld de eigenschap van het nieuwe ProductsRow exemplaar niet toe aan de geselecteerde waarde in de CategoryID DropDownList, maar wijs het toe aan een waarde zoals Categories. Hier i is de lusindexeerfunctie en heeft waarden tussen 1 en 5. Als u dus twee of meer producten toevoegt in batch, heeft het eerste product een geldige CategoryID waarde (5), maar volgende producten hebben CategoryID waarden die niet overeenkomen met CategoryID waarden in de Categories tabel. Het netto-effect is dat terwijl de eerste INSERT slaagt, de daaropvolgende zullen mislukken met een schending van een vreemde-sleutelbeperking. Omdat de batchinvoeging atomisch is, wordt de eerste INSERT teruggedraaid en wordt de database teruggezet naar de status voordat het batchinvoegproces is gestart.

Samenvatting

In deze en de vorige twee zelfstudies hebben we interfaces gemaakt die het mogelijk maken om batches met gegevens bij te werken, te verwijderen en in te voegen, die allemaal gebruikmaken van de transactieondersteuning die we hebben toegevoegd aan de Data Access-laag in de wijzigingen in de wrapping-database in een transactiezelfstudie . Voor bepaalde scenario's verbeteren dergelijke batchverwerkingsgebruikersinterfaces de efficiëntie van eindgebruikers aanzienlijk door het aantal klikken, postbacks en schakelopties voor toetsenbord-naar-muis te verlagen, terwijl ook de integriteit van de onderliggende gegevens behouden blijft.

Deze zelfstudie rondt onze kijk op het werken met batchgegevens af. In de volgende reeks zelfstudies worden verschillende geavanceerde Data Access Layer-scenario's besproken, waaronder het gebruik van opgeslagen procedures in de TableAdapter-methoden, het configureren van instellingen op verbindings- en opdrachtniveau in de DAL, het versleutelen van verbindingsreeksen en meer.

Veel plezier met programmeren!

Over de auteur

Scott Mitchell, auteur van zeven ASP/ASP.NET-boeken en oprichter van 4GuysFromRolla.com, werkt sinds 1998 met Microsoft-webtechnologieën. Scott werkt als onafhankelijk consultant, trainer en schrijver. Zijn laatste boek is Sams Teach Yourself ASP.NET 2.0 in 24 uur. Hij kan worden bereikt op mitchell@4GuysFromRolla.com.

Speciale dank aan

Deze tutorialreeks is beoordeeld door veel behulpzame beoordelers. Hoofdrevisoren voor deze zelfstudie waren Hilton Giesenow en S ren Jacob Lauritsen. Bent u geïnteresseerd in het bekijken van mijn aanstaande MSDN-artikelen? Zo ja, laat iets van je horen via mitchell@4GuysFromRolla.com.