Condividi tramite


Aggiornamento in blocco (C#)

di Scott Mitchell

Scaricare il PDF

Informazioni su come aggiornare più record di database in una singola operazione. Nel livello interfaccia utente viene creato un controllo GridView in cui ogni riga è modificabile. Nel livello di accesso ai dati viene eseguito l'incapsulamento di più operazioni di aggiornamento all'interno di una transazione per garantire che tutti gli aggiornamenti abbiano esito positivo o che venga eseguito il rollback di tutti gli aggiornamenti.

Introduzione

Nell'esercitazione precedente è stato illustrato come estendere il livello di accesso ai dati per aggiungere il supporto per le transazioni di database. Le transazioni di database garantiscono che una serie di istruzioni di modifica dei dati verrà considerata come un'unica operazione atomica, che garantisce che tutte le modifiche avranno esito negativo o tutte avranno esito positivo. Grazie a questa funzionalità DAL di basso livello, è possibile concentrarsi sulla creazione di interfacce di modifica dei dati batch.

In questa esercitazione verrà creato un controllo GridView in cui ogni riga è modificabile (vedere la figura 1). Poiché viene eseguito il rendering di ogni riga nell'interfaccia di modifica, non è necessaria una colonna di pulsanti Modifica, Aggiornamento e Annulla. Nella pagina sono invece presenti due pulsanti Aggiorna prodotti che, quando si fa clic, enumerano le righe gridView e aggiornano il database.

Ogni riga in GridView è modificabile

Figura 1: Ogni riga in GridView è modificabile (fare clic per visualizzare l'immagine a dimensione intera)

Iniziamo!

Annotazioni

Nell'esercitazione Esecuzione di aggiornamenti batch è stata creata un'interfaccia di modifica batch usando il controllo DataList. Questa esercitazione è diversa da quella precedente in che usa gridView e l'aggiornamento batch viene eseguito nell'ambito di una transazione. Dopo aver completato questa esercitazione, è consigliabile tornare all'esercitazione precedente e aggiornarla per usare la funzionalità relativa alle transazioni di database aggiunta nell'esercitazione precedente.

Esame dei passaggi per rendere modificabili tutte le righe gridView

Come illustrato nell'esercitazione Panoramica sull'inserimento, l'aggiornamento e l'eliminazione di dati, il GridView offre il supporto predefinito per la modifica dei dati sottostanti per ciascuna riga. Internamente, GridView annota quale riga è modificabile tramite la sua proprietà EditIndex. Poiché GridView è associato all'origine dati, controlla ogni riga per verificare se l'indice della riga è uguale al valore di EditIndex. In tal caso, i campi di quella riga vengono resi usando le loro interfacce di modifica. Per BoundFields, l'interfaccia di modifica è un controllo TextBox la cui Text proprietà è assegnata al valore del campo dati specificato dalla proprietà BoundField s DataField . Per TemplateFields, EditItemTemplate viene usato al posto di ItemTemplate.

Tenere presente che il flusso di lavoro di modifica inizia quando un utente fa clic sul pulsante Modifica di una riga. In questo modo viene generato un postback, la proprietà GridView viene impostata sull'indice EditIndex della riga selezionata e i dati sono riassociati alla griglia. Quando si fa clic sul pulsante Annulla di una riga, durante il postback EditIndex viene impostato su un valore di -1 prima di riassociare i dati alla griglia. Poiché le righe di GridView iniziano l'indicizzazione a zero, l'impostazione EditIndex su -1 ha l'effetto di visualizzare GridView in modalità di sola lettura.

La EditIndex proprietà funziona bene per la modifica per riga, ma non è progettata per la modifica in batch. Per rendere modificabile l'intero GridView, è necessario che ogni riga utilizzi l'interfaccia di modifica. Il modo più semplice per eseguire questa operazione consiste nel creare dove ogni campo modificabile viene implementato come TemplateField con la relativa interfaccia di modifica definita in ItemTemplate.

Nei diversi passaggi successivi verrà creato un controllo GridView completamente modificabile. Nel passaggio 1 si inizierà creando GridView e il relativo ObjectDataSource e convertirne BoundFields e CheckBoxField in TemplateFields. Nei passaggi 2 e 3 sposteremo le interfacce di modifica dai TemplateFields EditItemTemplate alle loro corrispondenti ItemTemplate.

Passaggio 1: Visualizzazione delle informazioni sul prodotto

Prima di preoccuparsi della creazione di un controllo GridView in cui sono modificabili le righe, è possibile iniziare visualizzando semplicemente le informazioni sul prodotto. Aprire la BatchUpdate.aspx pagina nella BatchData cartella e trascinare GridView dalla Toolbox nella Designer. Impostare GridView s ID su ProductsGrid e, dallo smart tag, scegliere di associarlo a un nuovo ObjectDataSource denominato ProductsDataSource. Configurare ObjectDataSource per recuperare i dati dalla classe ProductsBLL tramite il metodo GetProducts.

Configurare ObjectDataSource per l'utilizzo della classe ProductsBLL

Figura 2: Configurare ObjectDataSource per l'uso della classe (ProductsBLL a dimensione intera)

Recuperare i dati del prodotto usando il metodo GetProducts

Figura 3: Recuperare i dati del prodotto usando il metodo (GetProducts a dimensione intera)

Analogamente a GridView, le funzionalità di modifica di ObjectDataSource sono progettate per funzionare in base alle righe. Per aggiornare un set di record, è necessario scrivere un po' di codice nella classe code-behind della pagina ASP.NET che esegue il batch dei dati e lo passa al BLL. Pertanto, impostare gli elenchi a discesa nelle schede UPDATE, INSERT e DELETE di ObjectDataSource su (Nessuno). Fare clic su Fine per completare la procedura guidata.

Impostare gli elenchi di Drop-Down nelle schede UPDATE, INSERT e DELETE su (Nessuno)

Figura 4: Impostare gli elenchi di Drop-Down nelle schede UPDATE, INSERT e DELETE su (Nessuno) (Fare clic per visualizzare l'immagine a dimensione intera)

Dopo aver completato la procedura guidata Configura origine dati, il markup dichiarativo di ObjectDataSource dovrebbe essere simile al seguente:

<asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>

Il completamento della procedura guidata Configura origine dati fa sì che Visual Studio crei BoundFields e checkBoxField per i campi dati del prodotto in GridView. Per questa esercitazione, consentire all'utente di visualizzare e modificare solo il nome, la categoria, il prezzo e lo stato sospeso del prodotto. Rimuovere tutti i campi eccetto i ProductName, CategoryName, UnitPrice, e Discontinued e rinominare le proprietà dei primi tre campi rispettivamente in Product, Category e Price. Infine, selezionare le caselle di controllo Abilita paging e Abilita ordinamento nello smart tag gridView.

A questo punto GridView ha tre BoundFields (ProductName, CategoryNamee UnitPrice) e un CheckBoxField (Discontinued). È necessario convertire questi quattro campi in TemplateFields e quindi spostare l'interfaccia di modifica dai TemplateField EditItemTemplate al suo ItemTemplate.

Annotazioni

È stata esaminata la creazione e la personalizzazione di TemplateFields nell'esercitazione Personalizzazione dell'interfaccia di modifica dei dati. Verranno illustrati i passaggi per convertire BoundFields e CheckBoxField in TemplateFields e definire le relative interfacce di modifica nei rispettivi ItemTemplate s, ma se ci si blocca o è necessario un aggiornamento, non esitare a fare riferimento a questa esercitazione precedente.

Dallo smart tag di GridView, fare clic sul collegamento Modifica colonne per aprire la finestra di dialogo Campi. Selezionare quindi ogni campo e fare clic sul collegamento Converti questo campo in un campo modello.

Convertire i campi boundfield esistenti e CheckBoxField in templatefield

Figura 5: Convertire i campi boundfield esistenti e CheckBoxField in templatefield

Ora che ogni campo è un campo TemplateField, è possibile spostare l'interfaccia di modifica da EditItemTemplate s a ItemTemplate s.

Passaggio 2: Creazione delle ProductName, UnitPrice e Discontinued interfacce di modifica

La creazione delle interfacce di ProductName, UnitPrice e Discontinued è l'argomento di questo passaggio ed è piuttosto semplice, poiché ogni interfaccia è già definita nei TemplateField di EditItemTemplate. La creazione dell'interfaccia CategoryName di modifica è un po' più complessa perché è necessario creare un elenco a discesa delle categorie applicabili. Questa CategoryName interfaccia di modifica viene affrontata nel passaggio 3.

Iniziamo con ProductName TemplateField. Fare clic sul collegamento Modifica modelli dallo smart tag gridView e eseguire il ProductName drill-down in TemplateField s EditItemTemplate. Selezionare il controllo TextBox, copiarlo negli Appunti e incollarlo nell'oggetto ProductName TemplateField s ItemTemplate. Modificare la proprietà TextBox s ID in ProductName.

Aggiungere quindi un RequiredFieldValidator a ItemTemplate per assicurarsi che l'utente fornisca un valore per ogni nome del prodotto. Impostare la ControlToValidate proprietà su ProductName, la ErrorMessage proprietà su È necessario specificare il nome del prodotto. e impostare la proprietà Text a *. Dopo aver effettuato queste aggiunte al ItemTemplate, la schermata dovrebbe essere simile alla figura 6.

Il campo modello ProductName include ora un controllo TextBox e requiredFieldValidator

Figura 6: TemplateField ProductName include ora una casella di testo e un oggetto RequiredFieldValidator (fare clic per visualizzare l'immagine a dimensione intera)

Per l'interfaccia UnitPrice di modifica, iniziare copiando TextBox dall'oggetto EditItemTemplate a ItemTemplate. Successivamente, posizionare un $ davanti a TextBox e impostarne la ID proprietà su UnitPrice e la Columns proprietà su 8.

Aggiungi anche un CompareValidator ai segnaposto UnitPrice e ItemTemplate per assicurarti che il valore immesso dall'utente sia un valore di valuta valido, maggiore o uguale a 0,00 dollari. Impostare la proprietà del ControlToValidate validator su UnitPrice e la proprietà ErrorMessage su È necessario immettere un valore di valuta valido. Si ometta qualsiasi simbolo di valuta, la relativa Text proprietà su *, la relativa Type proprietà su Currency, la relativa Operator proprietà su GreaterThanEqual e la relativa ValueToCompare proprietà su 0.

Aggiungere un compareValidator per assicurarsi che il prezzo immesso sia un valore di valuta non negativo

Figura 7: Aggiungere un compareValidator per assicurarsi che il prezzo immesso sia un valore di valuta non negativo (fare clic per visualizzare l'immagine a dimensione intera)

Discontinued Per TemplateField è possibile usare il controllo CheckBox già definito in ItemTemplate. È sufficiente impostare il suo ID su Discontinued e la proprietà Enabled su true.

Passaggio 3: Creazione dell'interfacciaCategoryNamedi modifica

L'interfaccia di modifica nel CategoryName TemplateField EditItemTemplate contiene un TextBox che visualizza il valore del campo dati CategoryName. È necessario sostituirlo con un elenco a discesa che elenca le possibili categorie.

Annotazioni

Il tutorial Personalizzazione dell'interfaccia di modifica dei dati contiene una discussione più approfondita e completa sulla personalizzazione di un modello per includere un menu a discesa anziché un controllo TextBox. Anche se i passaggi qui sono completati, vengono presentati in modo conciso. Per un'analisi più approfondita della creazione e della configurazione delle categorie DropDownList, fare riferimento all'esercitazione Personalizzazione dell'interfaccia di modifica dei dati.

Trascina un elenco a discesa dalla casella degli strumenti nel campo modello CategoryNameItemTemplate, impostando il suo ID su Categories. A questo punto, di solito si definisce l'origine dati della DropDownList tramite il suo smart tag, creando un nuovo ObjectDataSource. Tuttavia, questo aggiungerà ObjectDataSource all'interno di ItemTemplate, che comporterà la creazione di un'istanza ObjectDataSource per ogni riga gridView. Invece, creiamo l'ObjectDataSource al di fuori dei TemplateFields del GridView. Terminare la modifica del modello e trascinare ObjectDataSource dalla casella degli strumenti nella finestra di progettazione sotto ProductsDataSource ObjectDataSource. Denominare il nuovo ObjectDataSource CategoriesDataSource e configurarlo per usare il metodo della classe CategoriesBLLGetCategories.

Configurare ObjectDataSource per l'uso della classe CategoriesBLL

Figura 8: Configurare ObjectDataSource per l'uso della classe (CategoriesBLL a dimensione intera)

Recuperare i dati delle categorie usando il metodo GetCategories

Figura 9: Recuperare i dati delle categorie usando il metodo (GetCategories a dimensione intera)

Poiché objectDataSource viene usato solo per recuperare i dati, impostare gli elenchi a discesa nelle schede UPDATE e DELETE su (Nessuno). Fare clic su Fine per completare la procedura guidata.

Impostare gli elenchi di Drop-Down nelle schede UPDATE e DELETE su (Nessuno)

Figura 10: Impostare gli elenchi di Drop-Down nelle schede UPDATE e DELETE su (Nessuno) (Fare clic per visualizzare l'immagine a dimensione intera)

Dopo aver completato la procedura guidata, il markup dichiarativo di CategoriesDataSource deve essere simile al seguente:

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Dopo aver creato e configurato CategoriesDataSource, tornare a CategoryName TemplateField ItemTemplate e, dallo smart tag DropDownList, fare clic sul link Scegli origine dati. Nella configurazione guidata dell'origine dati, selezionare l'opzione CategoriesDataSource nel primo elenco a discesa e scegliere di usare CategoryName per la visualizzazione e CategoryID per il valore.

Associare il DropDownList al CategoriesDataSource

Figura 11: Associare l'elenco a discesa a CategoriesDataSource (fare clic per visualizzare l'immagine a dimensione completa)

A questo punto l'elenco Categories a discesa elenca tutte le categorie, ma non seleziona ancora automaticamente la categoria appropriata per il prodotto associato alla riga GridView. A tale scopo, è necessario impostare Categories DropDownList SelectedValue sul valore del prodotto CategoryID. Fare clic sul collegamento Edit DataBindings (Modifica DataBindings) dallo smart tag DropDownList s e associare la SelectedValue proprietà al CategoryID campo dati, come illustrato nella figura 12.

Associare il valore CategoryID del prodotto alla proprietà SelectedValue di DropDownList

Figura 12: Associare il valore del CategoryID prodotto alla proprietà dropDownList s SelectedValue

Un ultimo problema rimane: se il prodotto non ha un CategoryID valore specificato, l'istruzione databinding su SelectedValue genererà un'eccezione. Ciò è dovuto al fatto che l'elenco a discesa contiene solo gli elementi per le categorie e non offre un'opzione per i prodotti che hanno un NULL valore di database per CategoryID. Per risolvere questo problema, impostare la proprietà DropDownList s AppendDataBoundItems su true e aggiungere un nuovo elemento a DropDownList, omettendo la Value proprietà dalla sintassi dichiarativa. Ovvero, assicurarsi che la Categories sintassi dichiarativa di DropDownList sia simile alla seguente:

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

Si noti come il <asp:ListItem Value=""> — Selezionare uno — abbia il relativo attributo Value impostato in modo esplicito su una stringa vuota. Torna all'esercitazione sulla personalizzazione dell'interfaccia di modifica dei dati per una discussione più approfondita sul perché questo elemento aggiuntivo di DropDownList è necessario per gestire il caso NULL e perché l'assegnazione della proprietà Value a una stringa vuota è essenziale.

Annotazioni

Qui è presente un potenziale problema di prestazioni e scalabilità che vale la pena menzionare. Poiché ogni riga ha un oggetto DropDownList che usa CategoriesDataSource come origine dati, il CategoriesBLL metodo della GetCategories classe verrà chiamato n volte per visita pagina, dove n è il numero di righe in GridView. Queste n chiamate a GetCategories risultano in n query al database. Questo impatto sul database può essere ridotto cachando le categorie restituite in una cache specifica per richiesta o tramite il livello di caching usando una dipendenza di caching SQL o una scadenza temporale molto breve.

Passaggio 4: Completamento dell'interfaccia di modifica

Sono state apportate numerose modifiche ai modelli di GridView senza sospendere la visualizzazione dello stato di avanzamento. Prenditi un momento per visualizzare i nostri progressi tramite un browser. Come illustrato nella figura 13, viene eseguito il rendering di ogni riga usando il relativo ItemTemplate, che contiene l'interfaccia di modifica della cella.

Ogni riga gridView è modificabile

Figura 13: Ogni riga gridView è modificabile (fare clic per visualizzare l'immagine a dimensione intera)

Ci sono alcuni problemi di formattazione minori che dovremmo occuparsi a questo punto. Prima di tutto, si noti che il UnitPrice valore contiene quattro punti decimali. Per risolvere il problema, tornare al UnitPrice TemplateFieldItemTemplate e, dallo Smart Tag del TextBox, fare clic sul collegamento Modifica DataBindings. Specificare quindi che la Text proprietà deve essere formattata come numero.

Formattare la proprietà

Figura 14: Formattare la Text proprietà come numero

In secondo luogo, allineare al centro la casella di controllo nella Discontinued colonna anziché allinearla a sinistra. Fare clic su Modifica colonne dallo smart tag gridView e selezionare Discontinued TemplateField nell'elenco dei campi nell'angolo inferiore sinistro. Eseguire il drill-down ItemStyle e impostare la proprietà HorizontalAlign su Centro come illustrato nella Figura 15.

Allineare al centro la casella di controllo interrotta

Figura 15: Centrare il Discontinued CheckBox

Aggiungere quindi un controllo ValidationSummary alla pagina e impostarne la ShowMessageBox proprietà su true e la relativa ShowSummary proprietà su false. Aggiungere anche i controlli Web Button che, quando si fa clic su di essi, aggiorneranno le modifiche effettuate dall'utente. In particolare, aggiungere due controlli Web Button, uno sopra GridView e uno sotto di esso, impostando entrambe le proprietà dei controlli Text su Update Products .

Poiché l'interfaccia di modifica di GridView è definita nei campi Template ItemTemplate, i EditItemTemplate sono superflui e possono essere rimossi.

Dopo aver apportato le modifiche di formattazione indicate in precedenza, aggiungendo i controlli Button e rimuovendo gli elementi non necessari EditItemTemplate , la sintassi dichiarativa della pagina dovrebbe essere simile alla seguente:

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

La figura 16 mostra questa pagina quando viene visualizzata tramite un browser dopo l'aggiunta dei controlli Web Button e le modifiche di formattazione apportate.

La pagina include ora due pulsanti Aggiorna prodotti

Figura 16: La pagina include ora due pulsanti Aggiorna prodotti (fare clic per visualizzare l'immagine a dimensione intera)

Passaggio 5: Aggiornamento dei prodotti

Quando un utente visita questa pagina, apporta le modifiche e quindi fa clic su uno dei due pulsanti Aggiorna prodotti. A questo punto è necessario salvare in qualche maniera i valori immessi dall'utente per ogni riga in un'istanza ProductsDataTable e poi passarlo a un metodo BLL che passerà quell'istanza ProductsDataTable al metodo DAL UpdateWithTransaction. Il metodo UpdateWithTransaction, che abbiamo creato nell'esercitazione precedente, garantisce che il batch di modifiche sia aggiornato come un'operazione atomica.

Creare un metodo denominato BatchUpdate in BatchUpdate.aspx.cs e aggiungere il codice seguente:

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);
}

Questo metodo inizia recuperando tutti i prodotti in una ProductsDataTable tramite una chiamata al metodo GetProducts della BLL. Enumera quindi la ProductGrid raccolta di RowsGridView. La Rows raccolta contiene un'istanza GridViewRow per ogni riga visualizzata in GridView. Poiché vengono visualizzate al massimo dieci righe per pagina, la raccolta di Rows GridView non avrà più di dieci elementi.

Per ogni riga, il ProductID viene prelevato dalla collezione DataKeys e il ProductsRow appropriato viene selezionato da ProductsDataTable. Ai quattro controlli di input TemplateField viene fatto riferimento a livello di codice e ai relativi valori assegnati alle proprietà dell'istanza ProductsRow . Dopo che i valori di ciascuna riga di GridView sono stati usati per aggiornare ProductsDataTable, viene passato al metodo UpdateWithTransaction del BLL che, come illustrato nell'esercitazione precedente, chiama semplicemente il metodo del DAL UpdateWithTransaction.

L'algoritmo di aggiornamento batch usato per questa esercitazione aggiorna ogni riga di ProductsDataTable che corrisponde a una riga in GridView, indipendentemente dal fatto che le informazioni sul prodotto siano state modificate. Sebbene tali aggiornamenti ciechi non siano in genere un problema di prestazioni, possono causare record superflui se si auditano le modifiche alla tabella di database. Nell'esercitazione Esecuzione di aggiornamenti batch abbiamo esaminato un'interfaccia di aggiornamento batch con la DataList e aggiunto codice che aggiornerebbe solo i record effettivamente modificati dall'utente. È possibile usare le tecniche di Esecuzione di aggiornamenti batch per aggiornare il codice in questa esercitazione, se necessario.

Annotazioni

Quando si associa l'origine dati a GridView tramite lo smart tag, Visual Studio assegna automaticamente i valori della chiave primaria dell'origine dati alla proprietà GridView.DataKeyNames Se l'oggetto ObjectDataSource non è stato associato a GridView tramite lo smart tag di GridView come descritto nel passaggio 1, sarà necessario impostare manualmente la proprietà DataKeyNames di GridView a "ProductID" per accedere al valore ProductID di ogni riga tramite la collezione DataKeys.

Il codice usato in BatchUpdate è simile a quello usato nei metodi BLL, UpdateProduct la differenza principale è che nei UpdateProduct metodi viene recuperata solo una singola ProductRow istanza dall'architettura. Il codice che assegna le proprietà di ProductRow è lo stesso sia tra i metodi UpdateProducts sia nel codice all'interno del ciclo foreach in BatchUpdate, così come il modello complessivo.

Per completare questa esercitazione, è necessario richiamare il BatchUpdate metodo quando si fa clic su uno dei pulsanti Aggiorna prodotti. Creare gestori eventi per gli Click eventi di questi due controlli Button e aggiungere il codice seguente nei gestori eventi:

BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message", 
    "alert('The products have been updated.');", true);

Prima di tutto viene effettuata una chiamata a BatchUpdate. ClientScript property Viene quindi usato per inserire JavaScript che visualizzerà una finestra di messaggio che legge I prodotti sono stati aggiornati.

Prenditi un minuto per testare questo codice. Visitare BatchUpdate.aspx attraverso un browser, modificare un numero di righe e fare clic su uno dei pulsanti Aggiorna Prodotti. Supponendo che non siano presenti errori di convalida dell'input, verrà visualizzata una finestra di messaggio che legge I prodotti sono stati aggiornati. Per verificare l'atomicità dell'aggiornamento, prendere in considerazione l'aggiunta di un vincolo casuale CHECK , ad esempio uno che non consente i UnitPrice valori 1234.56. Quindi da BatchUpdate.aspx modificare un numero di record, assicurandosi di impostare un valore del prodotto UnitPrice sul valore non consentito (1234.56). Questo dovrebbe generare un errore quando si fa clic su Aggiorna prodotti, mentre durante l'operazione batch le altre modifiche vengono ripristinate ai valori originali.

Metodo alternativoBatchUpdate

Il BatchUpdate metodo appena esaminato recupera tutti i prodotti dal metodo BLL e GetProducts quindi aggiorna solo i record visualizzati in GridView. Questo approccio è ideale se GridView non usa il paging, ma se lo fa, potrebbero esserci centinaia, migliaia o decine di migliaia di prodotti, ma solo dieci righe in GridView. In questo caso, ottenere tutti i prodotti dal database solo per modificare 10 di essi è minore dell'ideale.

In questi tipi di situazioni, considera di utilizzare il metodo seguente BatchUpdateAlternate:

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 inizia creando un nuovo vuoto ProductsDataTable denominato products. Viene quindi attraversata la raccolta Rows del GridView e per ogni riga vengono recuperate le informazioni specifiche sul prodotto usando il metodo BLL. GetProductByProductID(productID) L'istanza recuperata ProductsRow ha le relative proprietà aggiornate nello stesso modo di BatchUpdate, ma dopo l'aggiornamento della riga viene importata in products``ProductsDataTable tramite il metodo DataTable sImportRow(DataRow).

Dopo che il ciclo foreach si completa, products contiene un'istanza ProductsRow per ogni riga nel GridView. Poiché ognuna delle ProductsRow istanze è stata aggiunta a products (anziché aggiornata), se viene passata in modo cieco al UpdateWithTransaction metodo , ProductsTableAdapter tenterà di inserire ognuno dei record nel database. È invece necessario specificare che ognuna di queste righe è stata modificata (non aggiunta).

A tale scopo, è possibile aggiungere un nuovo metodo al BLL denominato UpdateProductsWithTransaction. UpdateProductsWithTransaction, illustrato di seguito, imposta il RowState di ciascuna delle istanze di ProductsRow nella ProductsDataTable a Modified e quindi passa il ProductsDataTable al metodo DAL UpdateWithTransaction.

public int UpdateProductsWithTransaction(Northwind.ProductsDataTable products)
{
    // Mark each product as Modified
    products.AcceptChanges();
    foreach (Northwind.ProductsRow product in products)
        product.SetModified();
    // Update the data via a transaction
    return UpdateWithTransaction(products);
}

Riassunto

GridView offre funzionalità di modifica predefinite per riga, ma non supporta la creazione di interfacce completamente modificabili. Come illustrato in questa esercitazione, queste interfacce sono possibili, ma richiedono un po ' di lavoro. Per creare un controllo GridView in cui ogni riga è modificabile, è necessario convertire i campi di GridView in TemplateFields e definire l'interfaccia di modifica all'interno di ItemTemplate s. Inoltre, i controlli Web di tipo pulsante "Aggiorna Tutti" devono essere aggiunti alla pagina, separatamente dal GridView. Questi gestori eventi dei pulsanti Click devono enumerare la raccolta di Rows GridView, memorizzare le modifiche in un ProductsDataTable, e passare le informazioni aggiornate al metodo BLL appropriato.

Nell'esercitazione successiva verrà illustrato come creare un'interfaccia per l'eliminazione batch. In particolare, ogni riga gridView includerà una casella di controllo e invece dei pulsanti Aggiorna tutto -tipo, saranno disponibili i pulsanti Elimina righe selezionate.

Buon programmatori!

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Può essere raggiunto a mitchell@4GuysFromRolla.com.

Grazie speciale a

Questa serie di esercitazioni è stata esaminata da molti revisori competenti. I revisori principali per questo tutorial sono stati Teresa Murphy e David Suru. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, mandami un messaggio a mitchell@4GuysFromRolla.com.