Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Lär dig hur du uppdaterar flera databasposter i en enda åtgärd. I användargränssnittsskiktet skapar vi en GridView där varje rad kan redigeras. I dataåtkomstlagret omsluter vi flera uppdateringsåtgärder i en transaktion för att säkerställa att alla uppdateringar lyckas eller att alla uppdateringar återställs.
Inledning
I föregående självstudie såg vi hur du utökar dataåtkomstlagret för att lägga till stöd för databastransaktioner. Databastransaktioner garanterar att en serie datamodifieringsinstruktioner behandlas som en atomisk åtgärd, vilket säkerställer att alla ändringar misslyckas eller att alla kommer att lyckas. Med den här DAL-funktionen på låg nivå är vi redo att fokusera på att skapa batchdatamodifieringsgränssnitt.
I den här självstudien skapar vi en GridView där varje rad kan redigeras (se bild 1). Eftersom varje rad återges i redigeringsgränssnittet behöver du inte ha någon kolumn med knapparna Redigera, Uppdatera och Avbryt. I stället finns det två knappar för Uppdateringsprodukter på sidan som, när du klickar på det, räknar upp GridView-raderna och uppdaterar databasen.
Bild 1: Varje rad i GridView kan redigeras (Klicka om du vill visa en bild i full storlek)
Låt oss komma igång!
Anmärkning
I självstudien Utför Batch-uppdateringar skapade vi ett batchredigeringsgränssnitt med hjälp av DataList-kontrollen. Den här självstudien skiljer sig från den tidigare genom att den använder en GridView och batchuppdateringen utförs inom räckvidden av en transaktion. När du har slutfört den här självstudien rekommenderar jag att du återgår till den tidigare självstudien och uppdaterar den för att använda databastransaktionsrelaterade funktioner som lades till i föregående självstudie.
Undersöka stegen för att göra alla GridView-rader redigerbara
Som beskrivs i självstudien En översikt över infogning, uppdatering och borttagning av data erbjuder GridView inbyggt stöd för redigering av underliggande data per rad. Internt noterar GridView vilken rad som är redigerbar via sinEditIndex egenskap. Eftersom GridView håller på att bindas till sin datakälla, kontrollerar den varje rad för att avgöra om radens index har samma värde som EditIndex. I så fall visas fältet i raden med hjälp av sina redigeringsgränssnitt. För BoundFields är redigeringsgränssnittet en TextBox vars Text egenskap tilldelas det värde av datafältet som specificeras av BoundFields DataField egenskap. För TemplateFields EditItemTemplate används i stället för ItemTemplate.
Kom ihåg att redigeringsarbetsflödet startar när en användare klickar på en rads redigera-knapp. Detta orsakar en postback, sätter GridView EditIndex-egenskapen till den klickade radens index och binder om data till rutnätet. När knappen Avbryt på en rad klickas på, och det sker en postback, anges EditIndex till ett värde av -1 innan data binds om till rutnätet. Eftersom raderna i GridView börjar indexeras på noll, innebär inställningen av EditIndex till -1 att GridView visas i skrivskyddat läge.
Egenskapen EditIndex fungerar bra för redigering per rad, men är inte avsedd för batchredigering. För att göra hela GridView redigerbart måste varje rad återges med dess redigeringsgränssnitt. Det enklaste sättet att åstadkomma detta är att skapa där varje redigerbart fält implementeras som ett TemplateField med dess redigeringsgränssnitt definierat i ItemTemplate.
Under de kommande stegen skapar vi en helt redigerbar GridView. I steg 1 börjar vi med att skapa GridView och dess ObjectDataSource och konvertera dess BoundFields och CheckBoxField till TemplateFields. I steg 2 och 3 flyttar vi redigeringsgränssnitten från TemplateFields EditItemTemplate till deras ItemTemplate .
Steg 1: Visa produktinformation
Innan vi oroar oss för att skapa en GridView där rader kan redigeras börjar vi med att helt enkelt visa produktinformationen. Öppna sidan BatchUpdate.aspx i BatchData mappen och dra en GridView från verktygslådan till designern. Ange GridView s ID till ProductsGrid och från dess smarta tagg väljer du att binda den till en ny ObjectDataSource med namnet ProductsDataSource. Konfigurera ObjectDataSource för att hämta dess data från ProductsBLL klassens GetProducts -metod.
Konfigurera ObjectDataSource för att använda klassen ProductsBLL
Bild 2: Konfigurera ObjectDataSource att använda ProductsBLL klassen (Klicka om du vill visa en bild i full storlek)
Bild 3: Hämta produktdata med hjälp av GetProducts metoden (Klicka om du vill visa en bild i full storlek)
Precis som GridView är ObjectDataSources ändringsfunktioner utformade för att fungera per rad. För att kunna uppdatera en uppsättning poster måste vi skriva lite kod i kod-bakom-klassen för ASP.NET-sidan som batchbearbetar datan och skickar den till BLL. Ange därför listrutorna i flikarna Update, INSERT och DELETE i ObjectDataSource till (Ingen). Klicka på Slutför för att slutföra guiden.
Bild 4: Ange Drop-Down-listorna i flikarna UPDATE, INSERT och DELETE till (Ingen) (Klicka om du vill visa en bild i full storlek)
När du har slutfört guiden Konfigurera datakälla bör ObjectDataSources deklarativa markering se ut så här:
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
Om du slutför guiden Konfigurera datakälla skapar Visual Studio även BoundFields och ett CheckBoxField för produktdatafälten i GridView. I den här självstudien tillåter vi bara att användaren visar och redigerar produktens namn, kategori, pris och utgångna status. Ta bort alla utom fälten ProductName, CategoryName, UnitPriceoch Discontinued och byt namn på egenskaperna för de tre första fälten HeaderText till Produkt, Kategori respektive Pris. Slutligen markerar du kryssrutorna Aktivera paginering och Aktivera sortering för GridViews smarttagg.
Nu har GridView tre BoundFields (ProductName, , och CategoryName) och ett CheckBoxField (UnitPriceDiscontinued). Vi måste konvertera dessa fyra fält till TemplateFields och sedan flytta redigeringsgränssnittet från TemplateField s EditItemTemplate till dess ItemTemplate.
Anmärkning
Vi har utforskat hur du skapar och anpassar TemplateFields i självstudien Anpassa datamodifieringsgränssnittet . Vi går igenom stegen för att konvertera BoundFields och CheckBoxField till TemplateFields och definiera deras redigeringsgränssnitt i deras ItemTemplate:ar, men om du fastnar eller behöver en uppdatering, tveka inte att gå tillbaka till den här tidigare handledningen.
Klicka på länken Redigera kolumner i GridViews smarta tagg för att öppna dialogrutan Fält. Välj sedan varje fält och klicka på länken Konvertera det här fältet till en TemplateField.
Bild 5: Konvertera befintliga BoundFields och CheckBoxField till TemplateField
Nu när varje fält är ett TemplateField är vi redo att flytta redigeringsgränssnittet från EditItemTemplate s till ItemTemplate s.
Steg 2: Skapa gränssnittenProductName,UnitPrice ochDiscontinuedredigera
Att skapa gränssnitten ProductName, UnitPrice och Discontinued för redigering är ämnet i det här steget och är ganska enkelt eftersom varje gränssnitt redan har definierats i TemplateFields EditItemTemplate. Att skapa redigeringsgränssnittet CategoryName är lite mer involverat eftersom vi behöver skapa en listruta med tillämpliga kategorier. Det här CategoryName redigeringsgränssnittet hanteras i steg 3.
Vi börjar med ProductName TemplateField. Klicka på länken Redigera mallar från GridViews smarta tagg och öka detaljnivån till ProductName TemplateFields EditItemTemplate. Välj textrutan, kopiera den till urklipp och klistra sedan in den i ProductName TemplateField ItemTemplate. Ändra TextBoxens egenskap ID till ProductName.
Lägg sedan till en RequiredFieldValidator i ItemTemplate för att säkerställa att användaren tillhandahåller ett värde för varje produkts namn. Ställ in ControlToValidate-egenskapen till ProductName, ErrorMessage-egenskapen till Du måste ange produktens namn. Egenskapen Text sätts till *. När du har gjort dessa tillägg till ItemTemplatebör skärmen se ut ungefär som i bild 6.
Bild 6: Mallfältet ProductName innehåller nu en textruta och en RequiredFieldValidator (Klicka om du vill visa en bild i full storlek)
För redigeringsgränssnittet UnitPrice börjar du med att kopiera textrutan från EditItemTemplate till ItemTemplate. Placera sedan en $ framför TextBox och ange dess ID egenskap till UnitPrice och dess Columns egenskap till 8 .
Lägg också till en CompareValidator till UnitPrice s ItemTemplate för att säkerställa att värdet som anges av användaren är ett giltigt valutavärde som är större än eller lika med 0,00 USD. Ställ in validerarens ControlToValidate-egenskap på UnitPrice och dess ErrorMessage-egenskap på Du måste ange ett giltigt valutavärde. Vänligen utelämna valutasymbolerna., dess Text egenskap till *, dess Type egenskap till Currency, dess Operator egenskap till GreaterThanEqual och dess ValueToCompare egenskap till 0 .
Bild 7: Lägg till en CompareValidator för att säkerställa att det angivna priset är ett icke-negativt valutavärde (klicka om du vill visa en bild i full storlek)
Discontinued För TemplateField kan du använda kryssrutan som redan har definierats i ItemTemplate. Ställ helt enkelt in dess ID till Avbruten och dess Enabled egenskap till true.
Steg 3: Skapa redigeringsgränssnittetCategoryName
Redigeringsgränssnittet i CategoryName TemplateField s EditItemTemplate innehåller en textruta som visar värdet för CategoryName datafältet. Vi måste ersätta detta med en listruta med möjliga kategorier.
Anmärkning
Handledningen Anpassa datamodifieringsgränssnittet innehåller en grundligare och mer komplett diskussion om anpassning av en mall för att inkludera en listruta istället för en textruta. Även om stegen här är slutförda visas de kortfattat. För en mer ingående titt på hur du skapar och konfigurerar kategorin Listruta, se till självstudien Anpassa datamodifieringsgränssnittet.
Dra en listruta från verktygslådan till CategoryName TemplateField s ItemTemplateoch ange dess ID till Categories. I det här läget definierar vi vanligtvis DropDownLists-datakällan via dess smarta tagg och skapar en ny ObjectDataSource. Detta lägger dock till ObjectDataSource i ItemTemplate, vilket resulterar i en ObjectDataSource-instans som skapas för varje GridView-rad. I stället ska vi skapa ObjectDataSource utanför GridViews TemplateFields. Avsluta mallredigeringen och dra en objektdata-källa från verktygslådan till designern under ProductsDataSource objektdata-källa. Namnge den nya ObjectDataSource CategoriesDataSource och konfigurera den för att använda CategoriesBLL-klassens GetCategories-metod.
Bild 8: Konfigurera ObjectDataSource att använda CategoriesBLL klassen (Klicka om du vill visa en bild i full storlek)
Bild 9: Hämta kategoridata med hjälp av GetCategories metoden (Klicka om du vill visa en bild i full storlek)
Eftersom den här ObjectDataSource bara används för att hämta data anger du listrutorna på flikarna UPPDATERA och TA BORT till (Ingen). Klicka på Slutför för att slutföra guiden.
Bild 10: Ange Drop-Down-listorna på flikarna UPPDATERA och TA BORT till (Ingen) (Klicka om du vill visa en bild i full storlek)
När du har slutfört guiden bör den CategoriesDataSource deklarativa markeringen se ut så här:
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
När du har skapat och konfigurerat CategoriesDataSource, går du tillbaka till CategoryName TemplateField ItemTemplate och klickar på Välj datakälla länken från DropDownLists smarta etikett. I guiden Konfiguration av datakälla väljer du CategoriesDataSource alternativet i den första listrutan och väljer att ha CategoryName använt för visningen och CategoryID som värde.
Bild 11: Binda listrutan till CategoriesDataSource (Klicka om du vill visa en bild i full storlek)
I det här läget Categories visar Listrutan alla kategorier, men den väljer ännu inte automatiskt lämplig kategori för den produkt som är bunden till raden GridView. För att uppnå detta måste vi ställa in Categories listrutorna SelectedValue till produktens CategoryID värde. Klicka på länken Redigera databindningar från listrutans smarta tagg och associera SelectedValue egenskapen med CategoryID datafältet enligt bild 12.
Bild 12: Binda produktens CategoryID värde till DropDownListegenskapen SelectedValue
Ett sista problem kvarstår: om produkten inte har något CategoryID angivet värde resulterar databinding-instruktionen på SelectedValue i ett undantag. Det beror på att listrutan endast innehåller objekt för kategorierna och inte erbjuder något alternativ för de produkter som har ett NULL databasvärde för CategoryID. Åtgärda detta genom att ange DropDownLists AppendDataBoundItems-egenskap till true och lägg till ett nytt objekt i Listrutan, och utelämna egenskapen Value från den deklarativa syntaxen. Kontrollera alltså att Categories listrutans deklarativa syntax ser ut så här:
<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>
Observera hur <asp:ListItem Value=""> -- Välj en -- har attributet Value uttryckligen angivet till en tom sträng. Gå tillbaka till självstudien Anpassa datamodifieringsgränssnittet för en mer ingående diskussion om varför det här ytterligare DropDownList-objektet behövs för att hantera NULL fallet och varför tilldelning av Value egenskapen till en tom sträng är nödvändig.
Anmärkning
Det finns ett potentiellt problem med prestanda och skalbarhet här som är värt att nämna. Eftersom varje rad har en Listruta som använder CategoriesDataSource som sin datakälla, kommer CategoriesBLL klassens GetCategories metod att kallas n gånger per sidbesök, där n är antalet rader i GridView. Dessa n-anrop leder till GetCategories frågor till databasen. Den här effekten på databasen kan minskas genom cachelagring av de returnerade kategorierna, antingen i cacheminnet per begäran eller via cachelagringslagret med hjälp av ett SQL-cachelagringsberoende eller en mycket kort tidsbaserad förfallotid.
Steg 4: Slutföra redigeringsgränssnittet
Vi har gjort ett antal ändringar i GridView-mallarna utan att pausa för att visa våra framsteg. Ta en stund att se våra framsteg via en webbläsare. Som bild 13 visar återges varje rad med dess ItemTemplate, som innehåller cellens redigeringsgränssnitt.
Bild 13: Varje GridView-rad kan redigeras (Klicka om du vill visa en bild i full storlek)
Det finns några mindre formateringsproblem som vi bör ta hand om just nu. Observera först att värdet UnitPrice innehåller fyra decimaler. Åtgärda detta genom att gå tillbaka till UnitPrice TemplateField s ItemTemplate och klicka på länken Redigera DataBindings från textrutans smarta tagg. Ange sedan att egenskapen Text ska formateras som ett tal.
Bild 14: Formatera egenskapen Text som ett tal
För det andra ska vi centrera kryssrutan Discontinued i kolumnen (i stället för att ha den vänsterjusterad). Klicka på Redigera kolumner från GridViews smarta tagg och välj Discontinued TemplateField i listan med fält i det nedre vänstra hörnet. Öka detaljnivån till ItemStyle och ställ in egenskapen HorizontalAlign på Center enligt bild 15.
Bild 15: Centrera kryssrutan Discontinued
Lägg sedan till en ValidationSummary-kontroll på sidan och ange dess ShowMessageBox egenskap till true och dess ShowSummary egenskap till false. Lägg också till knappwebbkontrollerna som, när du klickar på det, uppdaterar användarens ändringar. Mer specifikt lägger du till två knappwebbkontroller, en ovanför GridView och en under den, där båda kontrollernas Text egenskaper anges till Uppdatera produkter .
Eftersom GridViews redigeringsgränssnitt har definierats i dess TemplateFields ItemTemplate är EditItemTemplate s överflödiga och kan tas bort.
När du har gjort ovanstående formateringsändringar, lagt till knappkontrollerna och tagit bort onödiga EditItemTemplate s, bör sidans deklarativa syntax se ut så här:
<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>
Bild 16 visar den här sidan när den visas via en webbläsare efter att knappwebbkontrollerna har lagts till och formateringsändringarna har gjorts.
Bild 16: Sidan innehåller nu två knappar för uppdateringsprodukter (klicka om du vill visa en bild i full storlek)
Steg 5: Uppdatera produkterna
När en användare besöker den här sidan kommer de att göra sina ändringar och sedan klicka på någon av de två knapparna För att uppdatera produkter. Då måste vi på något sätt spara de användaringivna värdena för varje rad i en ProductsDataTable instans och sedan skicka dem till en BLL-metod som sedan skickar den ProductsDataTable instansen till DAL-metoden UpdateWithTransaction . Metoden UpdateWithTransaction , som vi skapade i föregående självstudie, säkerställer att batchen med ändringar uppdateras som en atomisk åtgärd.
Skapa en metod med namnet BatchUpdate i BatchUpdate.aspx.cs och lägg till följande kod:
private void BatchUpdate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = productsAPI.GetProducts();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Find the ProductsRow instance in products that maps to gvRow
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsRow product = products.FindByProductID(productID);
if (product != null)
{
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateWithTransaction(products);
}
Den här metoden börjar med att få tillbaka alla produkter i ett ProductsDataTable via ett anrop till BLL:s GetProducts-metod. Den räknar ProductGrid sedan upp GridView-samlingenRows. Samlingen Rows innehåller en GridViewRow instans för varje rad som visas i GridView. Eftersom vi visar högst tio rader per sida har GridView-samlingen Rows högst tio objekt.
För varje rad ProductID hämtas från DataKeys samlingen och lämplig ProductsRow väljs från ProductsDataTable. De fyra TemplateField-indatakontrollerna refereras programmässigt och deras värden tilldelas till instansens ProductsRow egenskaper. När varje GridView-rads värden har använts för att uppdatera ProductsDataTable, skickas den till BLL:s metod UpdateWithTransaction som, vilket vi såg i föregående självstudie, helt enkelt anropar DAL:s metod UpdateWithTransaction.
Batchuppdateringsalgoritmen som används för den här självstudien uppdaterar varje rad i ProductsDataTable som motsvarar en rad i GridView, oavsett om produktinformationen har ändrats. Även om sådana blinda uppdateringar vanligtvis inte är ett prestandaproblem kan de leda till överflödiga poster om du granskar ändringar i databastabellen. I självstudien Utför massuppdateringar utforskade vi ett gränssnitt för massuppdateringar med DataList och lade till kod som bara skulle uppdatera de register som faktiskt ändrades av användaren. Använd gärna teknikerna från Att utföra Batch-uppdateringar för att uppdatera koden i den här självstudien, om så önskas.
Anmärkning
När du binder datakällan till GridView via dess smarta tagg tilldelar Visual Studio automatiskt datakällans primära nyckelvärden till egenskapen GridView DataKeyNames . Om du inte band ObjectDataSource till GridView via den smarta taggen för GridView som beskrivs i steg 1 DataKeyNames, måste du manuellt ställa in GridView-egenskapen ProductID till ProductID för att få åtkomst till DataKeyNames-värdet för varje rad genom -samlingen.
Koden som används i BatchUpdate liknar den som används i BLL-metoderna UpdateProduct , den största skillnaden är att i UpdateProduct metoderna hämtas endast en enda ProductRow instans från arkitekturen. Koden som tilldelar egenskaperna ProductRow för är densamma mellan UpdateProducts metoderna och koden i loopen foreach i BatchUpdate, liksom det övergripande mönstret.
För att slutföra den här självstudien måste vi ha BatchUpdate-metoden anropad när någon av knapparna för uppdatering av produkter klickas på. Skapa händelsehanterare för händelserna i dessa Click två knappkontroller och lägg till följande kod i händelsehanterarna:
BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message",
"alert('The products have been updated.');", true);
Först görs ett anrop till BatchUpdate.
ClientScript property används för att mata in JavaScript som visar en meddelanderuta där det står Produkterna har uppdaterats.
Ta en minut att testa den här koden. Besök BatchUpdate.aspx via en webbläsare, redigera ett antal rader och klicka på någon av knapparna Uppdatera produkter. Förutsatt att det inte finns några indataverifieringsfel bör du se en meddelanderuta som läser Produkterna har uppdaterats. Om du vill verifiera atomiteten för uppdateringen kan du överväga att lägga till en slumpmässig CHECK begränsning, till exempel en som inte tillåter UnitPrice värden på 1234,56.
BatchUpdate.aspxFrån redigerar du sedan ett antal poster och ser till att ange ett av produktens UnitPrice värde till det förbjudna värdet ( 1234,56 ). Detta bör resultera i ett fel när du klickar på Uppdatera produkter, och att de andra ändringarna under batchåtgärden återställs till sina ursprungliga värden.
En alternativBatchUpdatemetod
Metoden BatchUpdate som vi precis undersökte hämtar alla produkter från BLL-metoden GetProducts och uppdaterar sedan bara de poster som visas i GridView. Den här metoden är idealisk om GridView inte använder paginering, men om den gör det kan det finnas hundratals, tusentals eller tiotusentals produkter, men bara tio rader i GridView. I sådana fall är det mindre än idealiskt att bara hämta alla produkter från databasen för att ändra 10 av dem.
För dessa typer av situationer bör du överväga att använda följande BatchUpdateAlternate metod i stället:
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 börjar med att skapa en ny tom ProductsDataTable med namnet products. Den går sedan igenom GridView-samlingen Rows och för varje rad hämtar den specifika produktinformationen med hjälp av BLL-metoden GetProductByProductID(productID) . Den hämtade ProductsRow instansen har sina egenskaper uppdaterade på samma sätt som BatchUpdate, men efter att ha uppdaterat raden importeras den till products``ProductsDataTablevia metoden DataTable sImportRow(DataRow).
Efter att foreach-loopen är slutförd innehåller products en ProductsRow-instans för varje rad i GridView. Eftersom var och en av ProductsRow-instanserna har lagts till i products (istället för att uppdateras), kommer UpdateWithTransaction att försöka infoga varje post i databasen om vi blint skickar dem till ProductsTableAdapter-metoden. I stället måste vi ange att var och en av dessa rader har ändrats (inte lagts till).
Detta kan åstadkommas genom att lägga till en ny metod i BLL-filen med namnet UpdateProductsWithTransaction.
UpdateProductsWithTransaction, som visas nedan, anger RowState för var och en av ProductsRow instanserna i ProductsDataTable till Modified och skickar sedan ProductsDataTable till DAL:s UpdateWithTransaction metod.
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);
}
Sammanfattning
GridView har inbyggda redigeringsfunktioner per rad, men saknar stöd för att skapa fullständigt redigerbara gränssnitt. Som vi såg i den här självstudien är sådana gränssnitt möjliga, men kräver lite arbete. För att skapa en GridView där varje rad kan redigeras måste vi konvertera GridView-fälten till TemplateFields och definiera redigeringsgränssnittet inom ItemTemplate s. Dessutom måste webbkontrollerna för knappen Uppdatera alla -type läggas till på sidan, separat från GridView. De här knapparnas Click händelsehanterare måste räkna upp GridView-samlingen Rows , lagra ändringarna i en ProductsDataTableoch skicka den uppdaterade informationen till lämplig BLL-metod.
I nästa självstudie får vi se hur du skapar ett gränssnitt för batchborttagning. I synnerhet innehåller varje GridView-rad en kryssruta och i stället för Uppdatera alla -type knappar har vi knapparna Ta bort markerade rader.
Lycka till med programmerandet!
Om författaren
Scott Mitchell, författare till sju ASP/ASP.NET-böcker och grundare av 4GuysFromRolla.com, har arbetat med Microsofts webbtekniker sedan 1998. Scott arbetar som oberoende konsult, tränare och författare. Hans senaste bok är Sams Teach Yourself ASP.NET 2.0 på 24 timmar. Han kan nås på mitchell@4GuysFromRolla.com.
Särskilt tack till
Den här självstudieserien granskades av många användbara granskare. Ansvariga granskare för den här handledningen var Teresa Murphy och David Suru. Vill du granska mina kommande MSDN-artiklar? Om så är fallet, hör av dig på mitchell@4GuysFromRolla.com.