Esecuzione di aggiornamenti batch (C#)
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).
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
.
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).
Figura 3: Recuperare le informazioni sui fornitori usando il GetSuppliers()
metodo (fare clic per visualizzare l'immagine a dimensione intera)
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.
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.
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 DataListItem
oggetto , è 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 Nothing
UpdateSupplierAddress
(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 Address
valori di colonna , City
e 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.