Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
door Scott Mitchell
Meer informatie over het bijwerken van meerdere databaserecords in één bewerking. In de gebruikersinterfacelaag bouwen we een GridView waar elke rij kan worden bewerkt. In de Data Access-laag verpakken we de meerdere updatebewerkingen binnen een transactie om ervoor te zorgen dat alle updates slagen of dat alle updates worden teruggedraaid.
Introductie
In de voorgaande zelfstudie hebben we gezien hoe we de Data Access-laag uitbreiden om ondersteuning voor databasetransacties toe te voegen. Databasetransacties garanderen dat een reeks instructies voor gegevenswijziging wordt behandeld als één atomische bewerking, waardoor alle wijzigingen mislukken of allemaal lukken. Met deze lage DAL-functionaliteit uit de weg, zijn we klaar om ons te richten op het creëren van interfaces voor batchgegevenswijziging.
In deze zelfstudie bouwen we een GridView waar elke rij kan worden bewerkt (zie afbeelding 1). Omdat elke rij wordt weergegeven in de bewerkingsinterface, is er geen kolom met knoppen Bewerken, Bijwerken en Annuleren nodig. In plaats daarvan zijn er twee knoppen Producten bijwerken op de pagina die, wanneer erop wordt geklikt, de GridView-rijen opsommen en de database bijwerken.
Afbeelding 1: Elke rij in de Rasterweergave kan worden bewerkt (klik om de afbeelding op volledige grootte weer te geven)
Laten we beginnen!
Opmerking
In de zelfstudie Batch-updates uitvoeren hebben we een interface voor batchbewerking gemaakt met behulp van het besturingselement DataList. Deze zelfstudie wijkt af van de vorige waarin een GridView wordt gebruikt en de batch-update wordt uitgevoerd binnen het bereik van een transactie. Na het voltooien van deze zelfstudie moedig ik u aan om terug te keren naar de eerdere zelfstudie en deze bij te werken voor het gebruik van de functionaliteit voor transactiegerelateerde databases die in de vorige zelfstudie zijn toegevoegd.
De stappen voor het bewerken van alle GridView-rijen bekijken
Zoals besproken in de zelfstudie Een overzicht van het invoegen, bijwerken en verwijderen van gegevens , biedt GridView ingebouwde ondersteuning voor het bewerken van de onderliggende gegevens per rij. Intern noteert GridView welke rij kan worden bewerkt via de EditIndex eigenschap. Aangezien de GridView wordt gebonden aan de gegevensbron, wordt elke rij gecontroleerd om te zien of de index van de rij gelijk is aan de waarde van EditIndex. Zo ja, dan worden de rijvelden weergegeven met behulp van hun bewerkingsinterfaces. Voor BoundFields is de bewerkingsinterface een tekstvak waarvan de Text-eigenschap de waarde krijgt van het gegevensveld dat is gespecificeerd door de BoundField's DataField-eigenschap. Voor TemplateFields wordt deze EditItemTemplate gebruikt in plaats van de ItemTemplate.
Zoals u weet, wordt de bewerkingswerkstroom gestart wanneer een gebruiker op de knop Bewerken van een rij klikt. Dit veroorzaakt een postback, stelt de GridView-eigenschap EditIndex in op de index van de geklikte rij en bindt de gegevens opnieuw aan de grid. Wanneer op de knop Annuleren van een rij wordt geklikt, wordt bij het terugzetten de EditIndex waarde ingesteld op een waarde van -1 voordat de gegevens opnieuw aan het raster worden gekoppeld. Omdat de rijen van GridView beginnen met indexering vanaf nul, zorgt het instellen van EditIndex op -1 ervoor dat de GridView in de modus alleen-lezen wordt weergegeven.
De EditIndex eigenschap werkt goed voor bewerking per rij, maar is niet ontworpen voor batchbewerking. Als u de volledige GridView bewerkbaar wilt maken, moeten we elke rij weergeven met behulp van de bewerkingsinterface. De eenvoudigste manier om dit te bereiken is door te maken waar elk bewerkbaar veld wordt geïmplementeerd als een TemplateField met de bewerkingsinterface die is gedefinieerd in de ItemTemplate.
In de volgende stappen maken we een volledig bewerkbare GridView. In stap 1 maken we eerst de GridView en de ObjectDataSource en converteren we de BoundFields en CheckBoxField naar TemplateFields. In stap 2 en 3 verplaatsen we de bewerkingsinterfaces van de TemplateFields EditItemTemplate naar de bijbehorende ItemTemplate.
Stap 1: Productgegevens weergeven
Voordat we ons zorgen maken over het maken van een GridView waar rijen kunnen worden bewerkt, laten we beginnen door gewoon de productgegevens weer te geven. Open de BatchUpdate.aspx pagina in de BatchData map en sleep een GridView van de Toolbox naar de Ontwerpweergave. Stel de ID van de GridView in op ProductsGrid en kies vervolgens via het slimme label om deze te koppelen aan een nieuwe ObjectDataSource met de naam ProductsDataSource. Configureer de ObjectDataSource om de gegevens op te halen uit de methode ProductsBLL van de klasse GetProducts.
Afbeelding 2: De ObjectDataSource configureren om de ProductsBLL klasse te gebruiken (klik om de afbeelding op volledige grootte weer te geven)
Afbeelding 3: De productgegevens ophalen met behulp van de GetProducts methode (klik om de afbeelding op volledige grootte weer te geven)
Net als bij GridView zijn de wijzigingsfuncties van ObjectDataSource ontworpen om per rij te werken. Als u een set records wilt bijwerken, moeten we een beetje code schrijven in de code-achterklasse van de ASP.NET pagina die de gegevens batcheert en doorgeeft aan de BLL. Stel daarom de vervolgkeuzelijsten in de tabbladen UPDATE, INSERT en DELETE van ObjectDataSource in op (Geen). Klik op Voltooien om de wizard te voltooien.
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 u de wizard Gegevensbron configureren hebt voltooid, moet de declaratieve markering van ObjectDataSource er als volgt uitzien:
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
Het voltooien van de wizard Gegevensbron configureren zorgt er ook voor dat Visual Studio BoundFields en een CheckBoxField maakt voor de productgegevensvelden in GridView. Voor deze zelfstudie kunnen we alleen toestaan dat de gebruiker de productnaam, categorie, prijs en status van het product kan bekijken en bewerken. Verwijder alles behalve de velden ProductName, CategoryName, UnitPrice en Discontinued en hernoem de HeaderText-eigenschappen van de eerste drie velden naar respectievelijk Product, Categorie en Prijs. Schakel ten slotte de selectievakjes 'Paging inschakelen' en 'Sorteren inschakelen' in de smart tag van de GridView in.
Op dit moment heeft de GridView drie BoundFields (ProductName, CategoryNameen UnitPrice) en een CheckBoxField (Discontinued). We moeten deze vier velden converteren naar TemplateFields en vervolgens de bewerkingsinterface van de TemplateFields EditItemTemplate naar ItemTemplatede bijbehorende interface verplaatsen.
Opmerking
We hebben het maken en aanpassen van TemplateFields verkend in de zelfstudie Aanpassing van de interface voor gegevenswijziging . We doorlopen de stappen voor het converteren van de BoundFields en CheckBoxField naar TemplateFields en het definiëren van hun bewerkingsinterfaces in hun ItemTemplate s, maar als u vastloopt of dingen opnieuw wilt bekijken, aarzel dan niet om terug te verwijzen naar deze eerdere tutorial.
Klik op de smart tag van GridView en vervolgens op de link 'Kolommen bewerken' om het dialoogvenster Velden te openen. Selecteer elk veld en klik vervolgens op de koppeling 'Dit veld converteren naar een TemplateField'.
Afbeelding 5: Bestaande BoundFields en CheckBoxField converteren naar TemplateField
Nu elk veld een TemplateField is, zijn we klaar om de bewerkingsinterface van de EditItemTemplate s naar de ItemTemplate s te verplaatsen.
Stap 2: de ProductName, UnitPrice en Discontinued bewerken interfaces maken
Het creëren van de ProductName, UnitPrice, en Discontinued bewerkingsinterfaces is het onderwerp van deze stap en is vrij eenvoudig, omdat elke interface al is gedefinieerd in de TemplateField EditItemTemplate. Het maken van de CategoryName bewerkingsinterface is iets ingewikkelder omdat we een vervolgkeuzelijst van de toepasselijke categorieën moeten maken. Deze CategoryName bewerkingsinterface wordt in stap 3 aangepakt.
Laten we beginnen met templatefield ProductName . Klik op de koppeling Sjablonen bewerken vanuit de smarttag van GridView en zoom in op templatefields ProductNameEditItemTemplate. Selecteer het tekstvak, kopieer het naar het klembord en plak deze vervolgens in templatefields ProductNameItemTemplate. Wijzig de eigenschap van het Tekstvak ID in ProductName.
Voeg vervolgens een verplichte veldvalidator toe aan ItemTemplate om ervoor te zorgen dat er een waarde wordt opgegeven voor elke productnaam. Stel de ControlToValidate eigenschap in op ProductName, de ErrorMessage eigenschap op U moet de naam van het product opgeven. en de Text eigenschap instellen op *. Nadat u deze toevoegingen aan het ItemTemplatescherm hebt gemaakt, moet uw scherm er ongeveer uitzien als afbeelding 6.
Afbeelding 6: Het ProductName TemplateField bevat nu een tekstvak en een RequiredFieldValidator (klik hier om de volledige afbeelding weer te geven)
Voor de UnitPrice bewerkingsinterface kopieert u eerst het tekstvak van de EditItemTemplate naar de ItemTemplate. Plaats vervolgens een $ voor het tekstvak en stel de ID eigenschap ervan in op UnitPrice en de Columns eigenschap ervan op 8.
Voeg ook een CompareValidator toe aan de UnitPrice s ItemTemplate om ervoor te zorgen dat de waarde die door de gebruiker is ingevoerd een geldige valutawaarde is die groter is dan of gelijk is aan $ 0,00. Stel de validator eigenschap ControlToValidate in op UnitPrice, de eigenschap ErrorMessage op U moet een geldige valutawaarde invoeren. Laat alle valutasymbolen weg, de eigenschap Text op *, de eigenschap Type op Currency, de eigenschap Operator op GreaterThanEqual, en de eigenschap ValueToCompare op 0.
Afbeelding 7: Voeg een CompareValidator toe om ervoor te zorgen dat de ingevoerde prijs een niet-negatieve valutawaarde is (klik om de afbeelding op volledige grootte weer te geven)
Voor het Discontinued TemplateField kunt u het selectievakje gebruiken dat al is gedefinieerd in de ItemTemplate. Stel het ID in op Stopgezet en de Enabled eigenschap op true.
Stap 3: deCategoryNamebewerkingsinterface maken
De bewerkingsinterface in TemplateField CategoryName s EditItemTemplate bevat een tekstvak waarin de waarde van het CategoryName gegevensveld wordt weergegeven. We moeten dit vervangen door een vervolgkeuzelijst waarin de mogelijke categorieën worden vermeld.
Opmerking
De zelfstudie Over het aanpassen van de interface voor gegevenswijziging bevat een uitgebreidere en volledige discussie over het aanpassen van een sjabloon om een DropDownList op te nemen in plaats van een tekstvak. Hoewel de stappen hier compleet zijn, worden ze bondig gepresenteerd. Raadpleeg de zelfstudie Aanpassing van de interface voor gegevenswijziging voor een uitgebreider overzicht van het maken en configureren van de categorieën DropDownList.
Sleep een DropDownList van het Gereedschappenpalet naar de CategoryName TemplateField's ItemTemplate en stel de eigenschap ID in op Categories. Op dit moment definiëren we meestal de gegevensbron van de DropDownLists via de infotag, waardoor een nieuwe ObjectDataSource wordt gemaakt. Hiermee wordt echter de ObjectDataSource toegevoegd binnen de ItemTemplateobjectdatabron, wat resulteert in een ObjectDataSource-exemplaar dat voor elke GridView-rij is gemaakt. In plaats daarvan maken we de ObjectDataSource buiten de GridView s TemplateFields. Beëindig het bewerken van de sjabloon en sleep een ObjectDataSource van de Toolbox naar de ontwerper onder de ObjectDataSource ProductsDataSource. Geef de nieuwe ObjectDataSource CategoriesDataSource een naam en configureer het om de CategoriesBLL klasse de methode van GetCategories te laten gebruiken.
Afbeelding 8: De ObjectDataSource configureren om de CategoriesBLL klasse te gebruiken (klik om de afbeelding op volledige grootte weer te geven)
Afbeelding 9: De categoriegegevens ophalen met behulp van de GetCategories methode (klik om de afbeelding op volledige grootte weer te geven)
Omdat deze ObjectDataSource alleen wordt gebruikt om gegevens op te halen, stelt u de vervolgkeuzelijsten in op de tabbladen UPDATE en DELETE op (Geen). Klik op Voltooien om de wizard te voltooien.
Afbeelding 10: Stel de Drop-Down-lijsten in de tabbladen BIJWERKEN en VERWIJDEREN in op (Geen) (Klik om de volledige afbeelding weer te geven)
Nadat de wizard is voltooid, moet de CategoriesDataSource declaratieve markering er als volgt uitzien:
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
Met de CategoriesDataSource gemaakt en geconfigureerd, keer terug naar de CategoryName TemplateFields ItemTemplate en klik vanuit de slimme tag van de DropDownList op de koppeling Gegevensbron kiezen. Selecteer in de wizard Gegevensbronconfiguratie de CategoriesDataSource optie in de eerste vervolgkeuzelijst en kies ervoor om deze te gebruiken CategoryName voor de weergave en CategoryID als de waarde.
Afbeelding 11: Koppel de vervolgkeuzelijst aan de CategoriesDataSource (klik om de afbeelding op volledige grootte weer te geven)
Op dit moment worden in de Categories vervolgkeuzelijst alle categorieën weergegeven, maar wordt nog niet automatisch de juiste categorie geselecteerd voor het product dat is gebonden aan de rij GridView. Hiervoor moeten we de Categories vervolgkeuzelijst s SelectedValue instellen op de productwaarde CategoryID . Klik op de koppeling DataBindings bewerken vanuit de smart tag van DropDownList en koppel de SelectedValue eigenschap aan het CategoryID gegevensveld, zoals weergegeven in Afbeelding 12.
Afbeelding 12: De waarde van CategoryID het product binden aan de eigenschap DropDownList s SelectedValue
Een laatste probleem blijft: als het product geen waarde heeft CategoryID opgegeven, resulteert de gegevensbindingsinstructie SelectedValue in een uitzondering. Dit komt doordat de vervolgkeuzelijst alleen items voor de categorieën bevat en geen optie biedt voor die producten waarvoor een NULL databasewaarde CategoryIDis opgegeven. U kunt dit oplossen door de eigenschap DropDownList in AppendDataBoundItems te true stellen en een nieuw item toe te voegen aan de DropDownList, waarbij u de Value eigenschap weglaat uit de declaratieve syntaxis. Zorg er dus voor dat de declaratieve syntaxis van de Categories vervolgkeuzelijst er als volgt uitziet:
<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>
Let op hoe het <asp:ListItem Value=""> kenmerk -- Select One - Value expliciet is ingesteld op een lege tekenreeks. Raadpleeg de zelfstudie Over het aanpassen van de interface voor gegevenswijziging voor een uitgebreidere discussie over waarom dit extra DropDownList-item nodig is om de NULL case af te handelen en waarom de toewijzing van de Value eigenschap aan een lege tekenreeks essentieel is.
Opmerking
Er is hier een potentieel probleem met prestaties en schaalbaarheid dat de moeite waard is om te vermelden. Omdat elke rij een DropDownList heeft die de CategoriesDataSource als gegevensbron gebruikt, wordt de methode van CategoriesBLL de GetCategories klasse n keer per paginabezoek aangeroepen, waarbij n het aantal rijen in de GridView is. Deze n aanroepen van GetCategories resulteren in n queries naar de database. Deze impact op de database kan worden verminderd door de geretourneerde categorieën te cachen per aanvraag, of via de cachelaag met behulp van een SQL-caching afhankelijkheid of een zeer korte tijdsafhankelijk vervaldatum.
Stap 4: de bewerkingsinterface voltooien
We hebben een aantal wijzigingen aangebracht in de GridView-sjablonen zonder te onderbreken om onze voortgang weer te geven. Neem even de tijd om onze voortgang via een browser te bekijken. Zoals in afbeelding 13 wordt getoond, wordt elke rij gerenderd met behulp van zijn ItemTemplate, die de bewerkingsinterface van de cel bevat.
Afbeelding 13: Elke rasterweergaverij kan worden bewerkt (klik om de volledige afbeelding weer te geven)
Er zijn enkele kleine opmaakproblemen die we nu moeten oplossen. Houd er rekening mee dat de UnitPrice waarde vier decimalen bevat. U kunt dit oplossen door terug te gaan naar de UnitPrice TemplateFields ItemTemplate en, in de smart tag van de TextBox, te klikken op de koppeling DataBindings bewerken. Geef vervolgens op dat de Text eigenschap moet worden opgemaakt als een getal.
Afbeelding 14: De Text eigenschap opmaken als een getal
Ten tweede gaan we het selectievakje in de Discontinued kolom centreren (in plaats van dat het links is uitgelijnd). Klik op Kolommen bewerken in de smarttag van GridView en selecteer het Discontinued TemplateField in de lijst met velden in de linkerbenedenhoek. Zoom in ItemStyle en stel de HorizontalAlign eigenschap in op Center, zoals wordt weergegeven in afbeelding 15.
Afbeelding 15: Het selectievakje centreren Discontinued
Voeg vervolgens een validatiesamenvattingsbesturingselement toe aan de pagina en stel de ShowMessageBox eigenschap ervan true in op en de ShowSummary eigenschap ervan op false. Voeg ook de knopwebbesturingselementen toe die, wanneer erop wordt geklikt, de wijzigingen van de gebruiker bijwerken. Voeg met name twee knoppen voor webbesturing toe, één boven de GridView en één eronder, en stel de eigenschappen van beide knoppen Text in op Bijwerken van Producten.
Omdat de bewerkingsinterface van GridView is gedefinieerd in de templatefields ItemTemplate s, zijn de EditItemTemplate s overbodig en kunnen ze worden verwijderd.
Nadat u de bovenstaande opmaakwijzigingen hebt aangebracht, de knopbesturingselementen hebt toegevoegd en de overbodige EditItemTemplate waarden hebt verwijderd, moet de declaratieve syntaxis van uw pagina er als volgt uitzien:
<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>
In afbeelding 16 ziet u deze pagina in een browser nadat de webknoppen zijn toegevoegd en de opmaakwijzigingen zijn aangebracht.
Afbeelding 16: De pagina bevat nu twee updateproductenknoppen (klik hier om de volledige afbeelding weer te geven)
Stap 5: De producten bijwerken
Wanneer een gebruiker deze pagina bezoekt, brengt hij zijn/haar wijzigingen aan en klikt hij op een van de twee knoppen Producten bijwerken. Op dat moment moeten we de door de gebruiker ingevoerde waarden voor elke rij opslaan in een ProductsDataTable exemplaar en dat vervolgens doorgeven aan een BLL-methode die dat ProductsDataTable exemplaar vervolgens doorgeeft aan de DAL-methode UpdateWithTransaction . De UpdateWithTransaction methode, die we in de vorige zelfstudie hebben gemaakt, zorgt ervoor dat de batch met wijzigingen wordt bijgewerkt als een atomische bewerking.
Maak een methode met de naam BatchUpdate en BatchUpdate.aspx.cs voeg de volgende code toe:
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);
}
Deze methode begint met het terughalen van alle producten in een ProductsDataTable door een aanroep naar de methode van de BLL GetProducts. Vervolgens wordt de ProductGrid GridView-verzameling opgesomdRows. De Rows verzameling bevat een GridViewRow exemplaar voor elke rij die wordt weergegeven in de GridView. Omdat we maximaal tien rijen per pagina weergeven, heeft de verzameling GridView Rows niet meer dan tien items.
Voor elke rij wordt de ProductID uit de DataKeys verzameling opgehaald en wordt de juiste ProductsRow geselecteerd uit de ProductsDataTable. De vier sjabloonveldinvoerbesturingselementen worden programmatisch gebruikt, en hun waarden worden toegewezen aan de eigenschappen van het ProductsRow exemplaar. Nadat de waarden van elke GridView-rij zijn gebruikt om ProductsDataTable bij te werken, wordt deze doorgegeven aan de BLL's UpdateWithTransaction-methode, die, zoals we in de eerdere tutorial hebben gezien, eenvoudigweg de DAL's UpdateWithTransaction-methode aanroept.
Het batch-updatealgoritme dat voor deze zelfstudie wordt gebruikt, werkt elke rij in de ProductsDataTable rij bij die overeenkomt met een rij in GridView, ongeacht of de productgegevens zijn gewijzigd. Hoewel dergelijke blinde updates meestal geen prestatieprobleem zijn, kunnen ze leiden tot overbodige records als u wijzigingen in de databasetabel controleert. In de zelfstudie Batch-updates uitvoeren hebben we een interface voor batchupdates verkend met de DataList en code toegevoegd waarmee alleen de records worden bijgewerkt die daadwerkelijk door de gebruiker zijn gewijzigd. U kunt desgewenst de technieken van Het uitvoeren van Batch-updates gebruiken om de code in deze zelfstudie bij te werken.
Opmerking
Wanneer de gegevensbron via de slimme tag aan GridView wordt gekoppeld, wijst Visual Studio automatisch de primaire sleutelwaarde(s) van de gegevensbron toe aan de eigenschap GridView DataKeyNames . Als u de ObjectDataSource niet hebt gekoppeld aan GridView via de smarttag van GridView, zoals beschreven in stap 1, moet u de eigenschap GridView DataKeyNames handmatig instellen op ProductID om toegang te krijgen tot de ProductID waarde voor elke rij via de DataKeys verzameling.
De code gebruikt in BatchUpdate is vergelijkbaar met die in de BLL-methoden wordt gebruikt; het belangrijkste verschil is dat in de UpdateProduct-methoden slechts één UpdateProduct-exemplaar uit de ProductRow-architectuur wordt opgehaald. De code die de eigenschappen van de ProductRow code toewijst, is hetzelfde tussen de UpdateProducts methoden en de code binnen de foreach lus in BatchUpdate, net als het algemene patroon.
Om deze zelfstudie te voltooien, moet de BatchUpdate methode worden aangeroepen wanneer op een van de knoppen Producten bijwerken wordt geklikt. Maak gebeurtenis-handlers voor de Click gebeurtenissen van deze twee knopbesturingselementen en voeg de volgende code toe in de gebeurtenis-handlers:
BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message",
"alert('The products have been updated.');", true);
Eerst wordt een oproep gedaan naar BatchUpdate. Vervolgens wordt het ClientScript property gebruikt om JavaScript te injecteren waarmee een berichtenvak wordt weergegeven dat de producten zijn bijgewerkt.
Neem even de tijd om deze code te testen. Ga BatchUpdate.aspx via een browser, bewerk een aantal rijen en klik op een van de knoppen Producten bijwerken. Ervan uitgaande dat er geen invoervalidatiefouten zijn, ziet u een berichtvak met de melding dat de producten zijn bijgewerkt. Als u de atomiciteit van de update wilt controleren, kunt u overwegen een willekeurige CHECK beperking toe te voegen, zoals een beperking die geen waarden van 1234,56 toekent UnitPrice .
BatchUpdate.aspxBewerk vervolgens een aantal records en zorg ervoor dat u een van de productwaarden UnitPrice instelt op de verboden waarde (1234,56). Dit moet resulteren in een fout wanneer u op Producten bijwerken klikt terwijl de andere wijzigingen tijdens die batchbewerking zijn teruggedraaid naar de oorspronkelijke waarden.
Een alternatieveBatchUpdatemethode
De BatchUpdate methode die we zojuist hebben onderzocht, haalt alle producten op uit de methode BLL GetProducts en werkt vervolgens alleen de records bij die worden weergegeven in de GridView. Deze benadering is ideaal als rasterweergave geen paging gebruikt, maar als dit het geval is, zijn er mogelijk honderden, duizenden of tienduizenden producten, maar slechts tien rijen in de GridView. In dat geval is het ophalen van alle producten uit de database slechts om er 10 te wijzigen, kleiner dan ideaal.
Voor dergelijke situaties kunt u in plaats daarvan de volgende BatchUpdateAlternate methode gebruiken:
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 begint met het maken van een nieuwe lege ProductsDataTable genaamd products. Vervolgens wordt de collectie van de GridView Rows doorlopen en worden voor elke rij de specifieke productgegevens opgehaald met de BLL-methode GetProductByProductID(productID). Het opgehaalde ProductsRow exemplaar heeft zijn eigenschappen bijgewerkt op dezelfde manier als BatchUpdate, maar na het bijwerken van de rij wordt deze geïmporteerd in products``ProductsDataTable via de DataTable ImportRow(DataRow) methode.
Nadat de foreach lus is voltooid, products bevat het één ProductsRow exemplaar voor elke rij in GridView. Aangezien elk van de ProductsRow exemplaren aan de products is toegevoegd (in plaats van bijgewerkt), zal de UpdateWithTransaction proberen elk van de records in de database in te voegen als we deze blindelings aan de ProductsTableAdapter-methode doorgeven. In plaats daarvan moeten we opgeven dat elk van deze rijen is gewijzigd (niet toegevoegd).
Dit kan worden bereikt door een nieuwe methode toe te voegen aan de BLL met de naam UpdateProductsWithTransaction.
UpdateProductsWithTransaction, hieronder, stelt de RowState van elk van de ProductsRow exemplaren in de ProductsDataTable op Modified en geeft vervolgens de ProductsDataTable door aan de UpdateWithTransaction-methode van de DAL.
public int UpdateProductsWithTransaction(Northwind.ProductsDataTable products)
{
// Mark each product as Modified
products.AcceptChanges();
foreach (Northwind.ProductsRow product in products)
product.SetModified();
// Update the data via a transaction
return UpdateWithTransaction(products);
}
Samenvatting
GridView biedt ingebouwde bewerkingsmogelijkheden per rij, maar biedt geen ondersteuning voor het maken van volledig bewerkbare interfaces. Zoals we in deze zelfstudie hebben gezien, zijn dergelijke interfaces mogelijk, maar vereisen een beetje werk. Als u een GridView wilt maken waarin elke rij kan worden bewerkt, moeten we de velden van GridView converteren naar TemplateFields en de bewerkingsinterface binnen de ItemTemplate s definiëren. Bovendien moeten alle -type knopwebbesturingselementen worden toegevoegd aan de pagina, gescheiden van gridview. Deze knoppengebeurtenishandlers Click moeten de verzameling van GridView Rows doorlopen, de veranderingen opslaan in een ProductsDataTable, en de bijgewerkte informatie doorgeven aan de juiste BLL-methode.
In de volgende tutorial laten we zien hoe je een interface maakt voor batchverwijdering. In het bijzonder bevat elke GridView-regel een selectievakje en in plaats van de Update All -type-knoppen, hebben we de knoppen Geselecteerde rijen verwijderen.
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. Hoofdbeoordelaars voor deze handleiding waren Teresa Murphy en David Suru. Bent u geïnteresseerd in het bekijken van mijn aanstaande MSDN-artikelen? Zo ja, laat iets van je horen via mitchell@4GuysFromRolla.com.