Esecuzione di aggiornamenti batch (C#)

di Scott Mitchell

Scarica il PDF

Informazioni su come creare un Oggetto DataList completamente modificabile in cui tutti gli elementi sono in modalità di modifica e i cui valori possono essere salvati facendo clic su un pulsante "Aggiorna tutto" nella pagina.

Introduzione

Nell'esercitazione precedente è stato esaminato come creare un oggetto DataList a livello di elemento. Analogamente a GridView modificabile standard, ogni elemento di DataList includeva un pulsante Modifica che, quando si fa clic, renderebbe modificabile l'elemento. Anche se questa modifica a livello di elemento funziona bene per i dati che vengono aggiornati solo occasionalmente, alcuni scenari di casi d'uso richiedono all'utente di modificare molti record. Se un utente deve modificare decine di record ed è costretto a fare clic su Modifica, apportare le modifiche e fare clic su Aggiorna per ognuno di essi, la quantità di clic può ostacolare la produttività. In tali situazioni, un'opzione migliore consiste nel fornire un oggetto DataList completamente modificabile, uno in cui tutti gli elementi sono in modalità di modifica e i cui valori possono essere modificati facendo clic su un pulsante Aggiorna tutto nella pagina (vedere la figura 1).

Ogni elemento di un oggetto DataList completamente modificabile può essere modificato

Figura 1: Ogni elemento di un oggetto DataList completamente modificabile può essere modificato (fare clic per visualizzare l'immagine a dimensione intera)

In questa esercitazione verrà illustrato come consentire agli utenti di aggiornare le informazioni sugli indirizzi dei fornitori usando un DataList completamente modificabile.

Passaggio 1: Creare l'interfaccia utente modificabile in ItemTemplate di DataList

Nell'esercitazione precedente, in cui viene creato un DataList modificabile a livello di elemento standard, sono stati usati due modelli:

  • ItemTemplate contiene l'interfaccia utente di sola lettura (i controlli Web Etichetta per visualizzare il nome e il prezzo di ogni prodotto).
  • EditItemTemplate conteneva l'interfaccia utente della modalità di modifica (i due controlli Web TextBox).

La proprietà DataList determina EditItemIndex il DataListItem rendering (se presente) tramite .EditItemTemplate In particolare, il DataListItem cui ItemIndex valore corrisponde alla proprietà DataList viene EditItemIndex sottoposto a rendering utilizzando .EditItemTemplate Questo modello funziona bene quando è possibile modificare un solo elemento alla volta, ma si distingue quando si crea un Oggetto DataList completamente modificabile.

Per un Oggetto DataList completamente modificabile, è necessario eseguire il rendering di tutti gli DataListItem oggetti usando l'interfaccia modificabile. Il modo più semplice per eseguire questa operazione consiste nel definire l'interfaccia modificabile in ItemTemplate. Per modificare le informazioni sull'indirizzo dei fornitori, l'interfaccia modificabile contiene il nome del fornitore come testo e quindi textBoxes per i valori indirizzo, città e paese/area geografica.

Per iniziare, aprire la BatchUpdate.aspx pagina, aggiungere un controllo DataList e impostarne la ID proprietà su Suppliers. Dallo smart tag dataList, scegliere di aggiungere un nuovo controllo ObjectDataSource denominato SuppliersDataSource.

Creare un nuovo objectDataSource denominato SuppliersDataSource

Figura 2: Creare un nuovo oggettoDataSource denominato SuppliersDataSource (fare clic per visualizzare l'immagine a dimensione intera)

Configurare ObjectDataSource per recuperare i dati usando il SuppliersBLL metodo della GetSuppliers() classe (vedere la figura 3). Come per l'esercitazione precedente, invece di aggiornare le informazioni sul fornitore tramite ObjectDataSource, si userà direttamente con il livello della logica di business. Impostare quindi l'elenco a discesa su (Nessuno) nella scheda UPDATE (vedere la figura 4).

Recuperare le informazioni sui fornitori usando il metodo GetSuppliers()

Figura 3: Recuperare le informazioni sui fornitori usando il GetSuppliers() metodo (fare clic per visualizzare l'immagine a dimensione intera)

Impostare l'elenco Drop-Down su (Nessuno) nella scheda UPDATE

Figura 4: Impostare l'elenco Drop-Down su (Nessuno) nella scheda UPDATE (fare clic per visualizzare l'immagine a dimensione intera)

Al termine della procedura guidata, Visual Studio genera automaticamente l'oggetto DataList s ItemTemplate per visualizzare ogni campo dati restituito dall'origine dati in un controllo Web Etichetta. È necessario modificare questo modello in modo che fornisca invece l'interfaccia di modifica. L'oggetto ItemTemplate può essere personalizzato tramite il Designer usando l'opzione Modifica modelli dallo smart tag di DataList o direttamente tramite la sintassi dichiarativa.

Creare un'interfaccia di modifica che visualizzi il nome del fornitore come testo, ma include caselle di testo per l'indirizzo, la città e il paese/area geografica del fornitore. Dopo aver apportato queste modifiche, la sintassi dichiarativa della pagina dovrebbe essere simile alla seguente:

<asp:DataList ID="Suppliers" runat="server" DataKeyField="SupplierID"
    DataSourceID="SuppliersDataSource">
    <ItemTemplate>
        <h4><asp:Label ID="CompanyNameLabel" runat="server"
            Text='<%# Eval("CompanyName") %>' /></h4>
        <table border="0">
            <tr>
                <td class="SupplierPropertyLabel">Address:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Address" runat="server"
                        Text='<%# Eval("Address") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">City:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="City" runat="server"
                        Text='<%# Eval("City") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">Country:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Country" runat="server"
                        Text='<%# Eval("Country") %>' />
                </td>
            </tr>
        </table>
        <br />
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
</asp:ObjectDataSource>

Nota

Come per l'esercitazione precedente, DataList in questa esercitazione deve avere lo stato di visualizzazione abilitato.

ItemTemplate In sto usando due nuove classi CSS, SupplierPropertyLabel e SupplierPropertyValue, che sono stati aggiunti alla Styles.css classe e configurati per usare le stesse impostazioni di stile delle ProductPropertyLabel classi CSS e ProductPropertyValue .

.ProductPropertyLabel, .SupplierPropertyLabel
{
    font-weight: bold;
    text-align: right;
}
.ProductPropertyValue, .SupplierPropertyValue
{
    padding-right: 35px;
}

Dopo aver apportato queste modifiche, visitare questa pagina tramite un browser. Come illustrato nella figura 5, ogni elemento DataList visualizza il nome del fornitore come testo e usa TextBox per visualizzare l'indirizzo, la città e il paese.As Figure 5, each DataList item display the supplier name as text and uses TextBoxes to display the address, city, and country/region.

Ogni fornitore in DataList è modificabile

Figura 5: Ogni fornitore in DataList è modificabile (fare clic per visualizzare l'immagine a dimensione intera)

Passaggio 2: Aggiunta di un pulsante Aggiorna tutto

Anche se ogni fornitore nella figura 5 include i campi indirizzo, città e paese/area geografica visualizzati in un controllo TextBox, attualmente non è disponibile alcun pulsante Aggiorna. Invece di avere un pulsante Aggiorna per elemento, con datalist completamente modificabili è in genere presente un singolo pulsante Aggiorna tutto nella pagina che, quando si fa clic, aggiorna tutti i record in DataList. Per questa esercitazione, è possibile aggiungere due pulsanti Aggiorna tutto, uno nella parte superiore della pagina e uno nella parte inferiore (anche se facendo clic su uno dei due pulsanti avrà lo stesso effetto).

Per iniziare, aggiungere un controllo Web Button sopra DataList e impostarne la ID proprietà su UpdateAll1. Aggiungere quindi il secondo controllo Web Button sotto l'oggetto DataList, impostandone il ID valore su UpdateAll2. Impostare le Text proprietà per i due pulsanti su Aggiorna tutto. Infine, creare gestori eventi per entrambi gli eventi Buttons Click . Invece di duplicare la logica di aggiornamento in ognuno dei gestori eventi, è possibile effettuare il refactoring della logica in un terzo metodo, UpdateAllSupplierAddresses, con i gestori eventi semplicemente richiamando questo terzo metodo.

protected void UpdateAll1_Click(object sender, EventArgs e)
{
    UpdateAllSupplierAddresses();
}
protected void UpdateAll2_Click(object sender, EventArgs e)
{
    UpdateAllSupplierAddresses();
}
private void UpdateAllSupplierAddresses()
{
    // TODO: Write code to update _all_ of the supplier addresses in the DataList
}

La figura 6 mostra la pagina dopo l'aggiunta dei pulsanti Aggiorna tutto.

Alla pagina sono stati aggiunti due pulsanti Aggiorna tutti

Figura 6: Due pulsanti Aggiorna tutti sono stati aggiunti alla pagina (fare clic per visualizzare l'immagine a dimensione intera)

Passaggio 3: Aggiornamento di tutte le informazioni sull'indirizzo dei fornitori

Con tutti gli elementi di DataList che visualizzano l'interfaccia di modifica e con l'aggiunta dei pulsanti Aggiorna tutto, tutto ciò che rimane è scrivere il codice per eseguire l'aggiornamento batch. In particolare, è necessario scorrere gli elementi di DataList e chiamare il SuppliersBLL metodo della UpdateSupplierAddress classe per ognuno di essi.

È possibile accedere alla raccolta di DataListItem istanze che consentono l'accesso a DataList tramite la proprietà DataList.Items Con un riferimento a un DataListItemoggetto , è possibile acquisire il corrispondente SupplierID dalla DataKeys raccolta e fare riferimento a livello di codice ai controlli Web TextBox all'interno ItemTemplate di , come illustrato nel codice seguente:

private void UpdateAllSupplierAddresses()
{
    // Create an instance of the SuppliersBLL class
    SuppliersBLL suppliersAPI = new SuppliersBLL();
    // Iterate through the DataList's items
    foreach (DataListItem item in Suppliers.Items)
    {
        // Get the supplierID from the DataKeys collection
        int supplierID = Convert.ToInt32(Suppliers.DataKeys[item.ItemIndex]);
        // Read in the user-entered values
        TextBox address = (TextBox)item.FindControl("Address");
        TextBox city = (TextBox)item.FindControl("City");
        TextBox country = (TextBox)item.FindControl("Country");
        string addressValue = null, cityValue = null, countryValue = null;
        if (address.Text.Trim().Length > 0)
            addressValue = address.Text.Trim();
        if (city.Text.Trim().Length > 0)
              cityValue = city.Text.Trim();
        if (country.Text.Trim().Length > 0)
            countryValue = country.Text.Trim();
        // Call the SuppliersBLL class's UpdateSupplierAddress method
        suppliersAPI.UpdateSupplierAddress
            (supplierID, addressValue, cityValue, countryValue);
    }
}

Quando l'utente fa clic su uno dei pulsanti Aggiorna tutto, il UpdateAllSupplierAddresses metodo scorre ognuno DataListItem in Suppliers DataList e chiama il SuppliersBLL metodo della UpdateSupplierAddress classe, passando i valori corrispondenti. Un valore non immesso per l'indirizzo, la città o il paese/area geografica passa è un valore a NothingUpdateSupplierAddress (anziché una stringa vuota), che genera un database NULL per i campi del record sottostante.

Nota

Come miglioramento, è possibile aggiungere un controllo Web etichetta di stato alla pagina che fornisce un messaggio di conferma dopo l'esecuzione dell'aggiornamento batch.

Aggiornamento solo degli indirizzi modificati

L'algoritmo di aggiornamento batch usato per questa esercitazione chiama il UpdateSupplierAddress metodo per ogni fornitore in DataList, indipendentemente dal fatto che le informazioni sull'indirizzo siano state modificate. Anche se tali aggiornamenti ciechi non sono in genere un problema di prestazioni, possono causare record superflui se si controllano le modifiche alla tabella di database. Ad esempio, se si usano trigger per registrare tutti gli UPDATE elementi nella Suppliers tabella in una tabella di controllo, ogni volta che un utente fa clic sul pulsante Aggiorna tutto verrà creato un nuovo record di controllo per ogni fornitore del sistema, indipendentemente dal fatto che l'utente abbia apportato modifiche.

Le classi DataTable e DataAdapter ADO.NET sono progettate per supportare gli aggiornamenti batch in cui vengono generati solo record modificati, eliminati e nuovi record in qualsiasi comunicazione del database. Ogni riga di DataTable ha una RowState proprietà che indica se la riga è stata aggiunta a DataTable, eliminata, modificata o non modificata. Quando un oggetto DataTable viene inizialmente popolato, tutte le righe vengono contrassegnate come invariate. La modifica del valore di una delle colonne della riga contrassegna la riga come modificata.

SuppliersBLL Nella classe vengono aggiornate le informazioni sull'indirizzo del fornitore specificato leggendo prima il record del singolo fornitore in un SuppliersDataTable e quindi si impostano i Addressvalori di colonna , Citye Country usando il codice seguente:

public bool UpdateSupplierAddress
    (int supplierID, string address, string city, string country)
{
    Northwind.SuppliersDataTable suppliers =
        Adapter.GetSupplierBySupplierID(supplierID);
    if (suppliers.Count == 0)
        // no matching record found, return false
        return false;
    else
    {
        Northwind.SuppliersRow supplier = suppliers[0];
        if (address == null)
            supplier.SetAddressNull();
        else
            supplier.Address = address;
        if (city == null)
            supplier.SetCityNull();
        else
            supplier.City = city;
        if (country == null)
            supplier.SetCountryNull();
        else
            supplier.Country = country;
        // Update the supplier Address-related information
        int rowsAffected = Adapter.Update(supplier);
        // Return true if precisely one row was updated,
        // otherwise false
        return rowsAffected == 1;
    }
}

Questo codice assegna in modo ingenuo i valori di indirizzo, città e paese/area geografica passati a SuppliersRow in SuppliersDataTable indipendentemente dal fatto che i valori siano stati modificati o meno. Queste modifiche fanno sì che la SuppliersRow proprietà s RowState venga contrassegnata come modificata. Quando viene chiamato il metodo del livello di Update accesso ai dati, rileva che è SupplierRow stato modificato e quindi invia un UPDATE comando al database.

Si supponga, tuttavia, di aver aggiunto codice a questo metodo per assegnare solo i valori di indirizzo, città e paese/area geografica passati se sono diversi dai SuppliersRow valori esistenti. Nel caso in cui l'indirizzo, la città e il paese/area geografica siano gli stessi dei dati esistenti, non verranno apportate modifiche e gli SupplierRow oggetti RowState verranno lasciati contrassegnati come invariati. Il risultato netto è che, quando viene chiamato il metodo DAL, Update non verrà eseguita alcuna chiamata al database perché non SuppliersRow è stato modificato.

Per applicare questa modifica, sostituire le istruzioni che assegnano in modo cieco i valori di indirizzo, città e paese/area geografica passati con il codice seguente:

// Only assign the values to the SupplierRow's column values if they differ
if (address == null && !supplier.IsAddressNull())
    supplier.SetAddressNull();
else if ((address != null && supplier.IsAddressNull()) ||
         (!supplier.IsAddressNull() &&
         string.Compare(supplier.Address, address) != 0))
    supplier.Address = address;
if (city == null && !supplier.IsCityNull())
    supplier.SetCityNull();
else if ((city != null && supplier.IsCityNull()) ||
         (!supplier.IsCityNull() && string.Compare(supplier.City, city) != 0))
    supplier.City = city;
if (country == null && !supplier.IsCountryNull())
    supplier.SetCountryNull();
else if ((country != null && supplier.IsCountryNull()) ||
         (!supplier.IsCountryNull() &&
         string.Compare(supplier.Country, country) != 0))
    supplier.Country = country;

Con questo codice aggiunto, il metodo DAL Update invia un'istruzione UPDATE al database solo per i record i cui valori correlati all'indirizzo sono stati modificati.

In alternativa, è possibile tenere traccia dell'eventuale presenza di differenze tra i campi degli indirizzi passati e i dati del database e, in caso contrario, ignorare semplicemente la chiamata al metodo DAL.Update Questo approccio funziona correttamente se si usa il metodo diretto del database, poiché il metodo diretto del database non viene passato a un'istanza SuppliersRow di cui RowState è possibile verificare se è effettivamente necessaria una chiamata al database.

Nota

Ogni volta che viene richiamato il UpdateSupplierAddress metodo, viene effettuata una chiamata al database per recuperare informazioni sul record aggiornato. Quindi, se sono presenti modifiche ai dati, viene eseguita un'altra chiamata al database per aggiornare la riga della tabella. Questo flusso di lavoro può essere ottimizzato creando un UpdateSupplierAddress overload di metodo che accetta un'istanza EmployeesDataTable con tutte le modifiche apportate dalla BatchUpdate.aspx pagina. Quindi, potrebbe effettuare una chiamata al database per ottenere tutti i record dalla Suppliers tabella. È quindi possibile enumerare i due set di risultati e aggiornare solo i record in cui sono state apportate modifiche.

Riepilogo

In questa esercitazione è stato illustrato come creare un DataList completamente modificabile, consentendo a un utente di modificare rapidamente le informazioni sull'indirizzo per più fornitori. È stata avviata la definizione dell'interfaccia di modifica di un controllo Web TextBox per i valori di indirizzo, città e paese/area geografica del fornitore in DataList s ItemTemplate. Successivamente, sono stati aggiunti i pulsanti Aggiorna tutto sopra e sotto DataList. Dopo che un utente ha apportato le modifiche e fatto clic su uno dei pulsanti Aggiorna tutto, gli DataListItem oggetti vengono enumerati e viene eseguita una chiamata al SuppliersBLL metodo della UpdateSupplierAddress classe .

Buon programmatori!

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, lavora 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 all'indirizzo mitchell@4GuysFromRolla.com. o tramite il suo blog, disponibile all'indirizzo http://ScottOnWriting.NET.

Grazie speciale a

Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori principali di questa esercitazione sono stati Zack Jones e Ken Pespisa. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, rilasciami una riga in mitchell@4GuysFromRolla.com.