in

DotNetSide

Dot Net South Italy Developers User Group

Articoli

Articoli pubblicati dagli iscritti a .netSide

ADO.NET 2.0 e l'accesso ai dati asincrono

 

Autore: Michele Locuratolo (Mighell)

ADO.NET, nella sua versione 2.0, introduce molte novità utili a semplificare la vita di noi programmatori. Nel precedente articolo ci siamo occupati di MARS (Multiple Active Result Set) vedendo come questa funzionalità ci aiuta a risparmiare linee di codice e ad ottimizzare le nostre applicazioni.
In questo articolo vedremo invece come, grazie ad ADO.NET 2.0, possiamo accedere ai dati in maniera asincrona, evitando di bloccare la nostra applicazione durante l’esecuzione dei comandi.

L’accesso ai dati “normale”

Generalmente, quando si accede ad un Data Base per eseguire dei comandi, si usa un approccio denominato sincrono. Tale approccio è quello più “naturale” in quanto, quando scriviamo le nostre applicazioni, pensiamo spesso al flusso in cui le istruzioni devono essere eseguite.
I passi che facciamo quando interroghiamo una qualsiasi base dati sono generalmente i seguenti:

1. Apriamo la connessione al Data Base
2. Eseguiamo un comando, come una selezione di dati, un aggiornamento etc.
3. Attendiamo la fine del comando
4. Mostriamo i risultati all’utente
5. Chiudiamo la connessione al Data Base

Seguendo questo approccio, non consideriamo il caso in cui il comando che stiamo eseguendo richieda un tempo di esecuzione piuttosto lungo. Proviamo a pensare ad un comando come l’inserimento in massa di migliaia di record in un Data Base o all’aggiornamento di un catalogo piuttosto corposo. In questi casi, come sappiamo, l’applicazione resta bloccata finchè l’operazione non si è conclusa. Il blocco è causato dal fatto che l’esecuzione del comando avviene in modo sincrono, nello stesso thread in cui “vive” la nostra applicazione. Questo comportamento dell’applicazione è normale ma non è bello. Il blocco dell’interfaccia infatti ci impedisce di fare altre operazioni, come ad esempio la consultazione di altre aree dell’applicazione, o ancora ci impedisce di annullare il comando. A prescindere da questi due aspetti comunque negativi, il peggiore è la sensazione che l’utilizzatore ha della nostra applicazione. Vedere una applicazione congelata è brutto e può generare problemi ben più seri (vedi l’utente che chiude brutalmente l’applicazione dal Task Manager o, peggio ancora, riavvia il sistema).
La soluzione si chiama accesso asincrono.

L’accesso ai dati asincrono

Il principio di funzionamento di questa modalità di accesso ai dati è molto semplice: si esegue il comando in modalità asincrona appunto, usando uno dei comandi prefissati con la dicitura Begin, come ad esempio BeginExecuteReader o BeginExecuteNonQuery. Il runtime avvierà l’esecuzione del comando in thread separato lasciando libera l’interfaccia utente in modo da poter eseguire altre operazioni o annullare il comando. La sensazione che comunque avrà l’utente finale, sarà quella di una applicazione più responsiva e non bloccata.
Affinchè si possa usare questa modalità di accesso ai dati però, è necessario specificare il desiderio di operare in questo modo già nella stringa di connessione, impostando a true il parametro async. Non facendolo, verrà sollevata una eccezione. Questo ci fa già capire che la modalità di accesso asincona va usata solo quando serve, senza abusarne.
Diamo subito uno sguardo al codice:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace DotNetSide.Articles.AsyncDataAccess {
public partial class Form1 : Form {
public delegate void LabelHnd( string value );

public Form1() {
InitializeComponent();
}

private void btnStart_Click( object sender, EventArgs e ) {
SqlConnection myConnection = new SqlConnection();
myConnection.ConnectionString = "Data Source=.\\SQLEXPRESS;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=ProgrammareADONet;async=true";
myConnection.Open();
SqlCommand cmd = myConnection.CreateCommand();
cmd.CommandText = "WaitFor Delay '00:00:15' Select @@Version";
cmd.BeginExecuteReader( new AsyncCallback( ProcessResult ), cmd );
}

public void ProcessResult( IAsyncResult asyncRes ) {
SqlCommand cmd = (SqlCommand)asyncRes.AsyncState;
using ( cmd.Connection ) {
using ( cmd ) {
string DBVersion = string.Empty;
SqlDataReader myReader = cmd.EndExecuteReader( asyncRes );
if ( myReader.Read() ) {
DBVersion = myReader[0].ToString();
lbltextVersion.BeginInvoke( new LabelHnd( Update ), DBVersion );
}
}
}
}

public void Update( string text ) {
lbltextVersion.Text = text;
}
}
}

La prima cosa evidente, nella stringa di connessione, è il parametro async=true.
Per simulare un comando lungo, si è usato WaitFor Delay '00:00:15' Select @@Version che, dopo una attesa di 15 secondi, ritorna la versione del Data Base corrente. Lo stesso comportamento si sarebbe comunque ottenuto con un qualsiasi comando di lunga durata, più difficile però da simulare.
Per lanciare il comando in modalità asincrona, si è usato BeginExecuteReader che accetta come parametri il delegato da richiamare quando l’esecuzione del comando è completata ed un oggetto da passare alla procedura di callback.
In un thread separato verrà richiamato il metodo ProcessResult che eseguirà il comando lasciando attiva l’interfaccia utente. Al completamento dell’esecuzione, verrà aggiornata la label in interfaccia utente, anche qui passando da un Delegate.
Il risultato sarà quello di figura.

Conclusioni

Provando ad eseguire il codice dell’esempio, sarà evidente come l’interfaccia sarà ancora attiva e funzionante nonostante l’esecuzione del comando non sia stata ancora completata. Sebbene l’esempio utilizzato sia poco realistico, si pensi a quante volte, nelle nostre applicazioni, abbiamo incontrato questo problema. Un esempio più concreto è l’aggiornamento dei cataloghi. In Data Base con tabelle prodotti molto consistenti, l’aggiornamento del prezzo di vendita dell’intero listino è sempre una operazione abbastanza lunga e delicata. Se la nostra applicazione prevedere la possibilità di far compiere la suddetta operazione direttamente agli utenti (si spera con abilitazioni elevate), è buona norma prevedere questo tipo di modalità di accesso ai dati.

Only published comments... Oct 09 2006, 03:00 PM by DotNetSide Staff
Filed under:

Comments

 

Mighell's blog said:

Pubblicato oggi un mio articolo sull'accesso ai dati asincrono con ADO.Net 2.0Lo trovate qui. Ciao

October 9, 2006 8:13 PM
Powered by Community Server (Commercial Edition), by Telligent Systems