Inserimento batch (VB)
Informazioni su come inserire più record di database in una singola operazione. Nel livello dell'interfaccia utente si estende GridView per consentire all'utente di immettere più nuovi record. Nel livello di accesso ai dati vengono eseguite il wrapping di più operazioni di inserimento all'interno di una transazione per garantire che tutti gli inserimenti abbiano esito positivo o venga eseguito il rollback di tutti gli inserimenti.
Introduzione
Nell'esercitazione sull'aggiornamento in batch è stata esaminata la personalizzazione del controllo GridView per presentare un'interfaccia in cui erano modificabili più record. L'utente che visita la pagina potrebbe apportare una serie di modifiche e quindi, con un singolo clic sul pulsante, eseguire un aggiornamento batch. Per le situazioni in cui gli utenti aggiornano in genere molti record in un'unica operazione, tale interfaccia può salvare innumerevoli clic e cambi di contesto da tastiera a mouse rispetto alle funzionalità di modifica predefinite per riga esaminate di nuovo nell'esercitazione Panoramica di inserimento, aggiornamento ed eliminazione dei dati .
Questo concetto può essere applicato anche quando si aggiungono record. Si supponga che qui a Northwind Traders in genere riceviamo spedizioni da fornitori che contengono un certo numero di prodotti per una particolare categoria. Ad esempio, potremmo ricevere una spedizione di sei diversi prodotti per tè e caffè da Tokyo Traders. Se un utente immette i sei prodotti uno alla volta tramite un controllo DetailsView, dovrà scegliere molti degli stessi valori più e più volte: dovranno scegliere la stessa categoria (Bevande), lo stesso fornitore (Tokyo Traders), lo stesso valore sospeso (False) e le stesse unità per il valore dell'ordine (0). Questa voce di dati ripetitiva non solo richiede molto tempo, ma è soggetta a errori.
Con un po' di lavoro è possibile creare un'interfaccia di inserimento batch che consente all'utente di scegliere il fornitore e la categoria una sola volta, immettere una serie di nomi di prodotto e prezzi unità e quindi fare clic su un pulsante per aggiungere i nuovi prodotti al database (vedere la figura 1). Man mano che ogni prodotto viene aggiunto, ProductName
ai relativi campi dati e UnitPrice
vengono assegnati i valori immessi in TextBoxes, mentre CategoryID
ai relativi valori e SupplierID
vengono assegnati i valori di DropDownLists nella parte superiore del modulo. I Discontinued
valori e UnitsOnOrder
vengono impostati rispettivamente sui valori hardcoded di False
e 0.
Figura 1: Interfaccia di inserimento batch (fare clic per visualizzare l'immagine a dimensione intera)
In questa esercitazione verrà creata una pagina che implementa l'interfaccia di inserimento batch illustrata nella figura 1. Come per le due esercitazioni precedenti, gli inserimenti verranno inclusi nell'ambito di una transazione per garantire l'atomicità. Iniziamo!
Passaggio 1: Creazione dell'interfaccia di visualizzazione
Questa esercitazione sarà costituita da una singola pagina divisa in due aree: un'area di visualizzazione e un'area di inserimento. L'interfaccia di visualizzazione, che verrà creata in questo passaggio, mostra i prodotti in un controllo GridView e include un pulsante denominato Process Product Shipment.The display interface, we'll create in this step, shows the products in a GridView and includes a button titled Process Product Shipment. Quando si fa clic su questo pulsante, l'interfaccia di visualizzazione viene sostituita con l'interfaccia di inserimento, illustrata nella figura 1. L'interfaccia di visualizzazione viene restituita dopo aver fatto clic sui pulsanti Aggiungi prodotti da Spedizione o Annulla. Verrà creata l'interfaccia di inserimento nel passaggio 2.
Quando si crea una pagina con due interfacce, una sola delle quali è visibile alla volta, ogni interfaccia viene in genere inserita all'interno di un controllo Web panel, che funge da contenitore per altri controlli. Pertanto, la pagina avrà due controlli Panel uno per ogni interfaccia.
Per iniziare, aprire la BatchInsert.aspx
pagina nella BatchData
cartella e trascinare un pannello dalla casella degli strumenti nella Designer (vedere la figura 2). Impostare la proprietà Panel s ID
su DisplayInterface
. Quando si aggiunge Il pannello al Designer, le relative Height
proprietà e Width
sono impostate rispettivamente su 50px e 125px. Cancellare questi valori di proprietà dal Finestra Proprietà.
Figura 2: Trascinare un pannello dalla casella degli strumenti nella Designer (fare clic per visualizzare l'immagine a dimensione intera)
Trascinare quindi un controllo Button e GridView nel pannello. Impostare la proprietà Button s ID
su ProcessShipment
e la relativa Text
proprietà su Elabora spedizione prodotto. Impostare la proprietà gridView su ID
e, dallo smart tag, associarla a un nuovo ObjectDataSource denominato ProductsDataSource
.ProductsGrid
Configurare ObjectDataSource per eseguire il ProductsBLL
pull dei dati dal metodo della GetProducts
classe . Poiché gridView viene usato solo per visualizzare i dati, impostare gli elenchi a discesa nelle schede UPDATE, INSERT e DELETE su (Nessuno). Fare clic su Fine per completare la procedura guidata Configura origine dati.
Figura 3: Visualizzare i dati restituiti dal ProductsBLL
metodo della GetProducts
classe (fare clic per visualizzare l'immagine a dimensione intera)
Figura 4: Impostare il Drop-Down Elenchi nelle schede UPDATE, INSERT e DELETE su (Nessuno) (Fare clic per visualizzare l'immagine a dimensione intera)
Dopo aver completato la procedura guidata ObjectDataSource, Visual Studio aggiunge BoundFields e checkBoxField per i campi dati del prodotto. Rimuovere tutti i ProductName
campi , CategoryName
, SupplierName
, UnitPrice
e Discontinued
. È possibile effettuare qualsiasi personalizzazione estetica. Ho deciso di formattare il UnitPrice
campo come valore di valuta, riordinare i campi e rinominare diversi valori dei campi HeaderText
. Configurare anche GridView per includere il supporto per il paging e l'ordinamento selezionando le caselle di controllo Abilita paging e Abilita ordinamento nello smart tag di GridView.
Dopo aver aggiunto i controlli Panel, Button, GridView e ObjectDataSource e personalizzando i campi di GridView, il markup dichiarativo della pagina dovrebbe essere simile al seguente:
<asp:Panel ID="DisplayInterface" runat="server">
<p>
<asp:Button ID="ProcessShipment" runat="server"
Text="Process Product Shipment" />
</p>
<asp:GridView ID="ProductsGrid" runat="server" AllowPaging="True"
AllowSorting="True" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsDataSource">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True" SortExpression="SupplierName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False"
SortExpression="UnitPrice">
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued">
<ItemStyle HorizontalAlign="Center" />
</asp:CheckBoxField>
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
</asp:Panel>
Si noti che il markup per Button e GridView vengono visualizzati all'interno dei tag di apertura e chiusura <asp:Panel>
. Poiché questi controlli si trovano all'interno del DisplayInterface
pannello, è possibile nasconderli semplicemente impostando la proprietà Panel s Visible
su False
. Il passaggio 3 esamina la modifica a livello di codice della proprietà Panel s Visible
in risposta a un clic di un pulsante per visualizzare un'interfaccia nascondendo l'altra.
Dedicare qualche minuto a visualizzare lo stato di avanzamento tramite un browser. Come illustrato nella figura 5, verrà visualizzato un pulsante Process Product Shipment sopra un controllo GridView che elenca i prodotti dieci alla volta.
Figura 5: GridView Elenchi le funzionalità di ordinamento e ordinamento e paging offerte (fare clic per visualizzare l'immagine a dimensione intera)
Passaggio 2: Creazione dell'interfaccia di inserimento
Al termine dell'interfaccia di visualizzazione, è possibile creare l'interfaccia di inserimento. Per questa esercitazione, è possibile creare un'interfaccia di inserimento che richiede un singolo fornitore e valore di categoria e quindi consente all'utente di immettere fino a cinque nomi di prodotto e valori di prezzo unitario. Con questa interfaccia, l'utente può aggiungere uno a cinque nuovi prodotti che condividono tutti la stessa categoria e fornitore, ma hanno nomi di prodotto e prezzi univoci.
Per iniziare, trascinare un pannello dalla casella degli strumenti nella Designer, posizionandolo sotto il pannello esistenteDisplayInterface
. Impostare la ID
proprietà di questo pannello InsertingInterface
appena aggiunto su e impostarne la Visible
proprietà su False
. Aggiungeremo il codice che imposta la InsertingInterface
proprietà Panel s Visible
su True
nel passaggio 3. Cancellare anche i valori delle proprietà e Width
del Height
pannello.
Successivamente, è necessario creare l'interfaccia di inserimento visualizzata di nuovo nella figura 1. Questa interfaccia può essere creata tramite un'ampia gamma di tecniche HTML, ma verrà usata una tabella a quattro colonne, sette righe.
Nota
Quando si immette markup per gli elementi HTML <table>
, si preferisce usare la visualizzazione Origine. Anche se Visual Studio dispone di strumenti per l'aggiunta <table>
di elementi tramite il Designer, il Designer sembra tutto troppo disposto a inserire le impostazioni non inserite nel style
markup. Dopo aver creato il <table>
markup, in genere torno al Designer per aggiungere i controlli Web e impostarne le proprietà. Quando si creano tabelle con colonne e righe predeterminato, è preferibile usare codice HTML statico anziché il controllo Web Table perché è possibile accedere a tutti i controlli Web posizionati all'interno di un controllo Web Tabella solo usando il FindControl("controlID")
modello. Tuttavia, si usano controlli Web tabella per tabelle di dimensioni dinamiche (quelle le cui righe o colonne sono basate su alcuni criteri specificati dall'utente o di database), poiché il controllo Web Tabella può essere costruito a livello di codice.
Immettere il markup seguente all'interno dei <asp:Panel>
tag del InsertingInterface
pannello:
<table class="DataWebControlStyle" cellspacing="0">
<tr class="BatchInsertHeaderRow">
<td class="BatchInsertLabel">Supplier:</td>
<td></td>
<td class="BatchInsertLabel">Category:</td>
<td></td>
</tr>
<tr class="BatchInsertRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertAlternatingRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertAlternatingRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertFooterRow">
<td colspan="4">
</td>
</tr>
</table>
Questo <table>
markup non include ancora controlli Web, che verranno aggiunti momentaneamente. Si noti che ogni <tr>
elemento contiene un'impostazione specifica della classe CSS: BatchInsertHeaderRow
per la riga di intestazione in cui andranno i dropdownlist del fornitore e della categoria; BatchInsertFooterRow
per la riga del piè di pagina in cui verranno aggiunti i pulsanti Aggiungi prodotti dalla spedizione e annulla; e i valori alternati BatchInsertRow
e BatchInsertAlternatingRow
per le righe che conterranno i controlli TextBox del prodotto e del prezzo unitario. Ho creato classi CSS corrispondenti nel Styles.css
file per dare all'interfaccia di inserimento un aspetto simile ai controlli GridView e DetailsView usati in queste esercitazioni. Queste classi CSS sono illustrate di seguito.
/*** Styles for ~/BatchData/BatchInsert.aspx tutorial ***/
.BatchInsertLabel
{
font-weight: bold;
text-align: right;
}
.BatchInsertHeaderRow td
{
color: White;
background-color: #900;
padding: 11px;
}
.BatchInsertFooterRow td
{
text-align: center;
padding-top: 5px;
}
.BatchInsertRow
{
}
.BatchInsertAlternatingRow
{
background-color: #fcc;
}
Con questo markup immesso, tornare alla visualizzazione Struttura. Verrà <table>
visualizzata come tabella a quattro colonne, sette righe nella Designer, come illustrato nella figura 6.
Figura 6: L'interfaccia di inserimento è costituita da una tabella a quattro colonne Seven-Row (fare clic per visualizzare l'immagine a dimensione intera)
È ora possibile aggiungere i controlli Web all'interfaccia di inserimento. Trascinare due elenchi DropDownList dalla casella degli strumenti nelle celle appropriate nella tabella 1 per il fornitore e una per la categoria.
Impostare la proprietà Suppliers
supplier DropDownList su ID
e associarla a un nuovo ObjectDataSource denominato SuppliersDataSource
. Configurare il nuovo ObjectDataSource per recuperare i dati dal SuppliersBLL
metodo della GetSuppliers
classe e impostare l'elenco a discesa della scheda UPDATE su (Nessuno). Fare clic su Fine per completare la procedura guidata.
Figura 7: Configurare ObjectDataSource per l'uso del SuppliersBLL
metodo della GetSuppliers
classe (fare clic per visualizzare l'immagine a dimensione intera)
Suppliers
Fare in modo che DropDownList visualizzi il CompanyName
campo dati e usi il SupplierID
campo dati come ListItem
valori.
Figura 8: Visualizzare il CompanyName
campo dati e usare SupplierID
come valore (fare clic per visualizzare l'immagine a dimensione intera)
Denominare il secondo Oggetto DropDownList Categories
e associarlo a un nuovo ObjectDataSource denominato CategoriesDataSource
. Configurare ObjectDataSource per usare il CategoriesDataSource
CategoriesBLL
metodo della GetCategories
classe. Impostare gli elenchi a discesa nelle schede UPDATE e DELETE su (Nessuno) e fare clic su Fine per completare la procedura guidata. Infine, l'elenco a discesa visualizza il CategoryName
campo dati e usa come CategoryID
valore.
Dopo aver aggiunto e associato a ObjectDataSources configurati in modo appropriato, la schermata dovrebbe essere simile alla figura 9.
Figura 9: La riga di intestazione contiene ora gli Suppliers
elenchi a discesa e Categories
(fare clic per visualizzare l'immagine full-size)
È ora necessario creare textBoxes per raccogliere il nome e il prezzo per ogni nuovo prodotto. Trascinare un controllo TextBox dalla casella degli strumenti nella Designer per ognuna delle cinque righe del prodotto e dei prezzi. Impostare le ID
proprietà di TextBoxes su ProductName1
, UnitPrice3
UnitPrice1
ProductName2
UnitPrice2
ProductName3
e così via.
Aggiungere un CompareValidator dopo ogni casella di testo del prezzo unitario, impostando la proprietà sull'oggetto ControlToValidate
appropriato ID
. Impostare anche la Operator
proprietà su GreaterThanEqual
, ValueToCompare
su 0 e Type
su Currency
. Queste impostazioni indicano a CompareValidator di assicurarsi che il prezzo, se immesso, sia un valore di valuta valido maggiore o uguale a zero. Impostare la Text
proprietà su *e ErrorMessage
su Il prezzo deve essere maggiore o uguale a zero. Inoltre, omettere qualsiasi simbolo di valuta.
Nota
L'interfaccia di inserimento non include alcun controllo RequiredFieldValidator, anche se il ProductName
campo nella Products
tabella di database non consente NULL
i valori. Ciò è dovuto al fatto che si vuole consentire all'utente di immettere fino a cinque prodotti. Ad esempio, se l'utente deve specificare il nome del prodotto e il prezzo unitario per le prime tre righe, lasciando le ultime due righe vuote, è sufficiente aggiungere tre nuovi prodotti al sistema. Poiché ProductName
è necessario, tuttavia, è necessario verificare a livello di codice che se viene immesso un prezzo unitario, viene specificato un valore del nome del prodotto corrispondente. Questo controllo verrà affrontato nel passaggio 4.
Quando si convalida l'input dell'utente, compareValidator segnala dati non validi se il valore contiene un simbolo di valuta. Aggiungere un $ davanti a ogni casella di testo del prezzo unitario da usare come segnale visivo che indica all'utente di omettere il simbolo di valuta quando si immette il prezzo.
Infine, aggiungere un controllo ValidationSummary all'interno del InsertingInterface
pannello, impostare la relativa ShowMessageBox
proprietà su True
e la relativa ShowSummary
proprietà su False
. Con queste impostazioni, se l'utente immette un valore di prezzo di unità non valido, verrà visualizzato un asterisco accanto ai controlli TextBox incriminati e la casella di messaggio ValidationSummary visualizzerà una casella di messaggio lato client che mostra il messaggio di errore specificato in precedenza.
A questo punto, la schermata dovrebbe essere simile alla figura 10.
Figura 10: l'interfaccia di inserimento include ora caselle di testo per i nomi e i prezzi dei prodotti (fare clic per visualizzare l'immagine full-size)
È quindi necessario aggiungere i pulsanti Aggiungi prodotti da Spedizione e Annulla alla riga piè di pagina. Trascinare due controlli Button dalla casella degli strumenti nel piè di pagina dell'interfaccia di inserimento, impostando rispettivamente le proprietà Pulsanti ID
su AddProducts
e CancelButton
Text
e proprietà su Aggiungi prodotti da Spedizione e Annulla. Impostare inoltre la CancelButton
proprietà del controllo su CausesValidation
false
.
Infine, è necessario aggiungere un controllo Web etichetta che visualizzerà i messaggi di stato per le due interfacce. Ad esempio, quando un utente aggiunge correttamente una nuova spedizione di prodotti, si vuole tornare all'interfaccia di visualizzazione e visualizzare un messaggio di conferma. Se, tuttavia, l'utente fornisce un prezzo per un nuovo prodotto, ma lascia il nome del prodotto, è necessario visualizzare un messaggio di avviso poiché il ProductName
campo è obbligatorio. Poiché è necessario visualizzare questo messaggio per entrambe le interfacce, inserirlo nella parte superiore della pagina all'esterno dei pannelli.
Trascinare un controllo Web etichetta dalla casella degli strumenti nella parte superiore della pagina nella Designer. Impostare la proprietà su StatusLabel
, cancellare la Text
ID
proprietà e impostare le Visible
proprietà e EnableViewState
su False
. Come illustrato nelle esercitazioni precedenti, l'impostazione della EnableViewState
proprietà per False
consente di modificare a livello di codice i valori delle proprietà etichetta e di ripristinarne automaticamente le impostazioni predefinite nel postback successivo. Ciò semplifica il codice per visualizzare un messaggio di stato in risposta a un'azione dell'utente che scompare nel postback successivo. Impostare infine la StatusLabel
proprietà del CssClass
controllo su Warning, ovvero il nome di una classe CSS definita in che visualizza il testo in Styles.css
un carattere grande, corsivo, grassetto, rosso.
La figura 11 mostra la Designer di Visual Studio dopo l'aggiunta e la configurazione dell'etichetta.
Figura 11: Posizionare il controllo sopra i due controlli pannello (fare clic per visualizzare l'immagineStatusLabel
full-size)
Passaggio 3: Passaggio tra la visualizzazione e l'inserimento di interfacce
A questo punto è stato completato il markup per la visualizzazione e l'inserimento di interfacce, ma siamo ancora rimasti con due attività:
- Passaggio tra le interfacce di visualizzazione e inserimento
- Aggiunta dei prodotti nella spedizione al database
Attualmente, l'interfaccia di visualizzazione è visibile, ma l'interfaccia di inserimento è nascosta. Ciò avviee perché la DisplayInterface
proprietà Panel s è impostata su True
(il valore predefinito), mentre la InsertingInterface
proprietà Panel s Visible
Visible
è impostata su False
. Per passare tra le due interfacce è sufficiente attivare il valore della proprietà di Visible
ogni controllo.
Si vuole passare dall'interfaccia di visualizzazione all'interfaccia di inserimento quando viene fatto clic sul pulsante Process Product Spedizione. Creare pertanto un gestore eventi per l'evento Click
Button contenente il codice seguente:
Protected Sub ProcessShipment_Click(sender As Object, e As EventArgs) _
Handles ProcessShipment.Click
DisplayInterface.Visible = False
InsertingInterface.Visible = True
End Sub
Questo codice nasconde semplicemente il DisplayInterface
pannello e mostra il InsertingInterface
pannello.
Creare quindi gestori eventi per i controlli Add Products from Shipment e Cancel Button nell'interfaccia di inserimento. Quando si fa clic su uno di questi pulsanti, è necessario ripristinare l'interfaccia di visualizzazione. Creare Click
gestori eventi per entrambi i controlli Button in modo che chiamino ReturnToDisplayInterface
, un metodo che verrà aggiunto in modo momentaneo. Oltre a nascondere il pannello e a visualizzare il InsertingInterface
DisplayInterface
pannello, il ReturnToDisplayInterface
metodo deve restituire i controlli Web allo stato di pre-modifica. Ciò comporta l'impostazione delle proprietà DropDownLists SelectedIndex
su 0 e Text
la cancellazione delle proprietà dei controlli TextBox.
Nota
Si consideri ciò che potrebbe verificarsi se non sono stati restituiti i controlli allo stato di pre-modifica prima di tornare all'interfaccia di visualizzazione. Un utente potrebbe fare clic sul pulsante Processo spedizione prodotto, immettere i prodotti dalla spedizione e quindi fare clic su Aggiungi prodotti dalla spedizione. Aggiungere i prodotti e restituire l'utente all'interfaccia di visualizzazione. A questo punto l'utente potrebbe voler aggiungere un'altra spedizione. Quando si fa clic sul pulsante Process Product Shipment (Processo spedizione prodotto) si restituirà all'interfaccia di inserimento, ma i valori DropDownList e TextBox verranno comunque popolati con i valori precedenti.
Protected Sub AddProducts_Click(sender As Object, e As EventArgs) _
Handles AddProducts.Click
' TODO: Save the products
' Revert to the display interface
ReturnToDisplayInterface()
End Sub
Protected Sub CancelButton_Click(sender As Object, e As EventArgs) _
Handles CancelButton.Click
' Revert to the display interface
ReturnToDisplayInterface()
End Sub
Const firstControlID As Integer = 1
Const lastControlID As Integer = 5
Private Sub ReturnToDisplayInterface()
' Reset the control values in the inserting interface
Suppliers.SelectedIndex = 0
Categories.SelectedIndex = 0
For i As Integer = firstControlID To lastControlID
CType(InsertingInterface.FindControl _
("ProductName" + i.ToString()), TextBox).Text = String.Empty
CType(InsertingInterface.FindControl _
("UnitPrice" + i.ToString()), TextBox).Text = String.Empty
Next
DisplayInterface.Visible = True
InsertingInterface.Visible = False
End Sub
Entrambi Click
i gestori eventi chiamano semplicemente il ReturnToDisplayInterface
metodo, anche se si tornerà al gestore eventi Add Products from Shipment Click
nel passaggio 4 e aggiungere codice per salvare i prodotti. ReturnToDisplayInterface
inizia restituendo gli Suppliers
elenchi a discesa e Categories
alle prime opzioni. Le due costanti firstControlID
e lastControlID
contrassegnano i valori dell'indice di controllo iniziale e finale usati per assegnare un nome al prodotto e un valore unitario TextBox nell'interfaccia di inserimento e vengono usati nei limiti del For
ciclo che imposta le Text
proprietà dei controlli TextBox su una stringa vuota. Infine, le proprietà Pannelli Visible
vengono reimpostate in modo che l'interfaccia di inserimento sia nascosta e l'interfaccia di visualizzazione visualizzata.
Provare questa pagina in un browser. Quando si visita per la prima volta la pagina, si dovrebbe visualizzare l'interfaccia di visualizzazione come illustrato nella figura 5. Fare clic sul pulsante Processo spedizione prodotto. La pagina eseguirà il postback e verrà ora visualizzata l'interfaccia di inserimento, come illustrato nella figura 12. Facendo clic sui pulsanti Aggiungi prodotti da Spedizione o Annulla, si torna all'interfaccia di visualizzazione.
Nota
Durante la visualizzazione dell'interfaccia di inserimento, è necessario testare i CompareValidators nelle caselle di testo del prezzo unitario. Verrà visualizzata una casella di messaggio lato client quando si fa clic sul pulsante Aggiungi prodotti dalla spedizione con valori di valuta o prezzi non validi con un valore inferiore a zero.
Figura 12: l'interfaccia di inserimento viene visualizzata dopo aver fatto clic sul pulsante Elaborazione spedizione prodotto (fare clic per visualizzare l'immagine full-size)
Passaggio 4: Aggiunta dei prodotti
Tutto ciò che rimane per questa esercitazione consiste nel salvare i prodotti nel database nel gestore eventi Aggiungi prodotti dal gestore eventi Click
del pulsante di spedizione. Questa operazione può essere eseguita creando un'istanza e aggiungendo un'istanza ProductsDataTable
ProductsRow
per ognuno dei nomi dei prodotti forniti. Dopo aver aggiunto questi ProductsRow
elementi, verrà eseguita una chiamata al ProductsBLL
metodo della UpdateWithTransaction
classe che passa .ProductsDataTable
Si ricordi che il UpdateWithTransaction
metodo, creato di nuovo nell'esercitazione Modifiche del database di wrapping all'interno di un'esercitazione Sulle transazioni , passa il ProductsDataTable
metodo al ProductsTableAdapter
metodo 's UpdateWithTransaction
. Da qui viene avviata una transazione ADO.NET e tableAdapter genera un'istruzione INSERT
per il database per ogni aggiunta ProductsRow
in DataTable. Supponendo che tutti i prodotti vengano aggiunti senza errori, la transazione viene eseguito il commit, in caso contrario viene eseguito il rollback.
Il codice per il gestore eventi Add Products from Shipment Button deve Click
anche eseguire un po' di controllo degli errori. Poiché nell'interfaccia di inserimento non sono presenti oggetti RequiredFieldValidator, un utente potrebbe immettere un prezzo per un prodotto omettendone il nome. Poiché il nome del prodotto è obbligatorio, se tale condizione si svolge è necessario avvisare l'utente e non procedere con gli inserimenti. Il codice completo Click
del gestore eventi segue:
Protected Sub AddProducts_Click(sender As Object, e As EventArgs) _
Handles AddProducts.Click
' Make sure that the UnitPrice CompareValidators report valid data...
If Not Page.IsValid Then Exit Sub
' Add new ProductsRows to a ProductsDataTable...
Dim products As New Northwind.ProductsDataTable()
For i As Integer = firstControlID To lastControlID
' Read in the values for the product name and unit price
Dim productName As String = CType(InsertingInterface.FindControl _
("ProductName" + i.ToString()), TextBox).Text.Trim()
Dim unitPrice As String = CType(InsertingInterface.FindControl _
("UnitPrice" + i.ToString()), TextBox).Text.Trim()
' Ensure that if unitPrice has a value, so does productName
If unitPrice.Length > 0 AndAlso productName.Length = 0 Then
' Display a warning and exit this event handler
StatusLabel.Text = "If you provide a unit price you must also
include the name of the product."
StatusLabel.Visible = True
Exit Sub
End If
' Only add the product if a product name value is provided
If productName.Length > 0 Then
' Add a new ProductsRow to the ProductsDataTable
Dim newProduct As Northwind.ProductsRow = products.NewProductsRow()
' Assign the values from the web page
newProduct.ProductName = productName
newProduct.SupplierID = Convert.ToInt32(Suppliers.SelectedValue)
newProduct.CategoryID = Convert.ToInt32(Categories.SelectedValue)
If unitPrice.Length > 0 Then
newProduct.UnitPrice = Convert.ToDecimal(unitPrice)
End If
' Add any "default" values
newProduct.Discontinued = False
newProduct.UnitsOnOrder = 0
products.AddProductsRow(newProduct)
End If
Next
' If we reach here, see if there were any products added
If products.Count > 0 Then
' Add the new products to the database using a transaction
Dim productsAPI As New ProductsBLL()
productsAPI.UpdateWithTransaction(products)
' Rebind the data to the grid so that the products just added are displayed
ProductsGrid.DataBind()
' Display a confirmation (don't use the Warning CSS class, though)
StatusLabel.CssClass = String.Empty
StatusLabel.Text = String.Format( _
"{0} products from supplier {1} have been " & _
"added and filed under category {2}.", _
products.Count, Suppliers.SelectedItem.Text, Categories.SelectedItem.Text)
StatusLabel.Visible = True
' Revert to the display interface
ReturnToDisplayInterface()
Else
' No products supplied!
StatusLabel.Text =
"No products were added. Please enter the " & _
"product names and unit prices in the textboxes."
StatusLabel.Visible = True
End If
End Sub
Il gestore eventi inizia assicurandosi che la Page.IsValid
proprietà restituisca un valore di True
. Se restituisce False
, ciò significa che uno o più dei CompareValidator segnalano dati non validi. In tal caso, non si vuole tentare di inserire i prodotti immessi o di terminare con un'eccezione quando si tenta di assegnare il valore di prezzo dell'unità immesso dall'utente alla ProductsRow
proprietà s UnitPrice
.
Successivamente viene creata una nuova ProductsDataTable
istanza (products
). Viene usato un For
ciclo per eseguire l'iterazione tramite il nome del prodotto e gli unit price TextBox e le Text
proprietà vengono lette nelle variabili productName
locali e unitPrice
. Se l'utente ha immesso un valore per il prezzo unitario, ma non per il nome del prodotto corrispondente, viene StatusLabel
visualizzato il messaggio Se si specifica un prezzo unitario, è necessario includere anche il nome del prodotto e il gestore eventi viene chiuso.
Se è stato specificato un nome prodotto, viene creata una nuova ProductsRow
istanza usando il ProductsDataTable
metodo s NewProductsRow
. Questa nuova ProductsRow
proprietà dell'istanza ProductName
è impostata sul nome del prodotto corrente TextBox mentre le SupplierID
SelectedValue
proprietà e CategoryID
vengono assegnate alle proprietà dei DropDownList nell'intestazione dell'interfaccia di inserimento. Se l'utente ha immesso un valore per il prezzo del prodotto, viene assegnato alla ProductsRow
proprietà dell'istanza UnitPrice
. In caso contrario, la proprietà viene lasciata non assegnata, che comporta un NULL
valore per UnitPrice
nel database. Infine, le Discontinued
proprietà e UnitsOnOrder
vengono assegnate rispettivamente ai valori False
hardcoded e 0.
Dopo aver assegnato le proprietà all'istanza, viene aggiunto all'oggetto ProductsRow
ProductsDataTable
.
Al termine del For
ciclo, si verifica se sono stati aggiunti prodotti. L'utente può, dopo tutto, fare clic su Aggiungi prodotti dalla spedizione prima di immettere i nomi dei prodotti o i prezzi. Se è presente almeno un prodotto nel ProductsDataTable
metodo , viene chiamato il ProductsBLL
metodo della UpdateWithTransaction
classe. Successivamente, i dati vengono rimbalzi in ProductsGrid
GridView in modo che i prodotti appena aggiunti vengano visualizzati nell'interfaccia di visualizzazione. Viene StatusLabel
aggiornato per visualizzare un messaggio di conferma e viene ReturnToDisplayInterface
richiamato, nascondendo l'interfaccia di inserimento e mostrando l'interfaccia di visualizzazione.
Se non sono stati immessi prodotti, l'interfaccia di inserimento rimane visualizzata ma il messaggio Nessun prodotto è stato aggiunto. Immettere i nomi dei prodotti e i prezzi unità nelle caselle di testo.
La figura 13, 14 e 15 mostra le interfacce di inserimento e visualizzazione in azione. Nella figura 13 l'utente ha immesso un valore di prezzo unitario senza un nome di prodotto corrispondente. La figura 14 mostra l'interfaccia di visualizzazione dopo l'aggiunta di tre nuovi prodotti, mentre la figura 15 mostra due dei nuovi prodotti aggiunti in GridView (il terzo è nella pagina precedente).
Figura 13: Il nome di un prodotto è obbligatorio quando si immette un prezzo unitario (fare clic per visualizzare un'immagine di dimensioni intere)
Figura 14: Sono state aggiunte tre nuove verdure per i fornitori Mayumi (fare clic per visualizzare l'immagine a dimensione intera)
Figura 15: I nuovi prodotti sono disponibili nell'ultima pagina di GridView (fare clic per visualizzare l'immagine a dimensione intera)
Nota
La logica di inserimento batch usata in questa esercitazione esegue il wrapping degli inserimenti nell'ambito della transazione. Per verificarlo, introdurre intenzionalmente un errore a livello di database. Ad esempio, anziché assegnare la proprietà della CategoryID
nuova ProductsRow
istanza al valore selezionato in Categories
DropDownList, assegnarlo a un valore come i * 5
. Ecco i
l'indicizzatore del ciclo e ha valori compresi tra 1 e 5. Pertanto, quando si aggiungono due o più prodotti in batch inserire il primo prodotto avrà un valore valido CategoryID
(5), ma i prodotti successivi avranno CategoryID
valori che non corrispondono ai CategoryID
valori nella Categories
tabella. L'effetto netto è che, mentre il primo INSERT
avrà esito positivo, quelli successivi avranno esito negativo con una violazione del vincolo di chiave esterna. Poiché l'inserimento batch è atomico, verrà eseguito il rollback del primo INSERT
, restituendo il database allo stato prima dell'avvio del processo di inserimento batch.
Riepilogo
In questa e nelle due esercitazioni precedenti sono state create interfacce che consentono l'aggiornamento, l'eliminazione e l'inserimento di batch di dati, che hanno usato il supporto delle transazioni aggiunto al livello di accesso ai dati nell'esercitazione Wrapping delle modifiche del database all'interno di una transazione . Per determinati scenari, tali interfacce utente per l'elaborazione batch migliorano notevolmente l'efficienza dell'utente finale riducendo il numero di clic, postback e commutatori di contesto da tastiera a mouse, mantenendo allo stesso tempo l'integrità dei dati sottostanti.
Questa esercitazione completa l'analisi dell'uso dei dati in batch. Il set successivo di esercitazioni esplora diversi scenari avanzati del livello di accesso ai dati, tra cui l'uso di stored procedure nei metodi di TableAdapter, la configurazione delle impostazioni a livello di connessione e di comando in DAL, la crittografia delle stringhe di connessione e altro ancora.
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 Hilton Giesenow e S ren Jacob Lauritsen. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, rilasciami una riga in mitchell@4GuysFromRolla.com.