Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Provider connessioni e comandi per l'accesso ai dati

Creare connessioni con i database relazionali, sfruttando il .NET Framework
Creare connessioni con i database relazionali, sfruttando il .NET Framework
Link copiato negli appunti

È prassi comune memorizzare dati in database relazionali, perciò il .NET framework fornisce alcune tecniche e tecnologie per colloquiare con il DMBS, ognuna con i suoi pro e contro. È utile quindi avere una panoramica completa per poter scegliere l'approccio più adatto all'applicazione che si sta sviluppando.

In questo capitolo ci occuperemo quindi dell'accesso diretto al database per muoverci verso astrazioni sempre maggiori fino ad arrivare alla possibilità di memorizzare direttamente oggetti all'interno del database.

Provider

Per connettersi ad un database è necessario usare un provider dati, nel caso di Sql Server ad esempio il provider si trova nel namespace System.Data.SqlClient e risiede nell'assembly System.Data, che è automaticamente importato da ogni progetto. Ogni DMBS ha il suo specifico provider, se ad esempio vogliamo utilizzare oracle sarà necessario scaricare l'apposito provider (dal sito di Oracle).

Per comunicare con un database a "basso livello" si deve prima di tutto stabilire una connessione tramite un oggetto SqlConnection che sarà usato poi da altri oggetti, come ad esempio i SqlCommand per eseguire del codice SQL. Ecco ad esempio uno snippet di codice che recupera il numero di righe di una tabella:

using(SqlConnection conn = new SqlConnection(
     "Database=Northwind;Server=localhost\SQL2008;Integrated Security=SSPI"))
{
  using (SqlCommand cmd = new SqlCommand("select count(*) from customers", conn))
  {
    conn.Open();
    Console.WriteLine("Numero di clienti {0}", cmd.ExecuteScalar());
  }
}

L'aspetto più importante è che tutti gli oggetti sono racchiusi dentro clausole using affinché siano correttamente rilasciati dopo il loro utilizzo. Dato che le connessioni utilizzano risorse unmanaged, la corretta chiamata a IDisposable.Dispose (che viene automaticamente effettuata dallo using) è fondamentale per non avere memory leak. Il rischio maggiore a cui si va incontro, se ci si dimentica di rilasciare oggetti legati all'accesso dati, è che le connessioni rimangano aperte fino a raggiungere il numero massimo e quindi il programma non è più in grado di accedere al database.

Per stabilire la connessione si ha bisogno della sola stringa di connessione e i comandi a loro volta richiedono solamente il codice sql o il nome della stored procedure da eseguire e della connessione da utilizzare. La sequenza operativa è: aprire la connessione con il metodo Open() ed utilizzare poi uno dei metodi ExecuteXXX dell'oggetto SqlCommand. Nell'esempio in questione si è utilizzato ad esempio il metodo ExecuteScalar() che ritorna il valore della prima colonna nella prima riga del risultato della query, questo metodo viene quindi usato per tutte le query the restituiscono un solo valore, come ad esempio quelle in cui si chiede il numero di record.

Una situazione più reale è quella in cui si vuole recuperare un certo numero di righe di una tabella imponendo alcune condizioni sui dati:

using (SqlCommand cmd = new SqlCommand(
      @"select CustomerID, CompanyName from customers
        where CustomerID like @search + '%'", conn))
{
  cmd.Parameters.Add(new SqlParameter("@search", "a"));
  conn.Open();
  using (SqlDataReader dr = cmd.ExecuteReader())
  {
    while (dr.Read())
    {
      Console.WriteLine("Selezionato cliente Id {0} nome {1}", dr["CustomerID"], dr["CompanyName"]);
    }
  }
}

La differenza rispetto alla situazione precedente è che il testo della query contiene un parametro chiamato @search (il simbolo @ identifica un parametro in SqlServer) ed è quindi necessario creare un oggetto SqlParameter, valorizzarlo e poi inserirlo nella lista dei parametri del comando prima dell'esecuzione. Una volta che tutti i parametri sono stati impostati, si utilizza il metodo ExecuteReader() dell'oggetto SqlCommand, che restituisce un cursore sui dati sotto forma di SqlDataReader.

L'SqlDataReader deve assolutamente essere racchiuso anch'esso da una clausola using affinché venga rilasciato correttamente. Per scorrere tra i dati è sufficiente utilizzare un ciclo while sul risultato del metodo Read() che sposta il cursore al record successivo e ritorna false quando si passa oltre l'ultimo record. Per accedere ai valori delle varie colonne è sufficiente utilizzare l'indexer classico specificandone il nome.

Si sarebbe naturalmente potuto anche evitare di usare il parametro e comporre un'unica stringa con la condizione già cablata al suo interno ma questo approccio è sconsigliabile per vari motivi. Il primo è che comporre dinamicamente le query, in caso le condizioni provengano dall'utente, ci rende vulnerabili ad un sql injection, perchè il chiamante potrebbe inserire istruzioni sql per eseguire azioni non volute. Il secondo motivo è che il database riesce ad ottimizzare in maniera migliore le query con parametri: se si eseguiamo la stessa query per cento volte con cento valori differenti del parametro, SQL Server capisce che si tratta della stessa query ed è in grado di riutilizzare il piano di esecuzione precedente.

Accedere al database con oggetti SqlConnection e SqlCommand è un approccio di basso livello ed è utile solamente quando si vuole avere il controllo completo del codice SQL, ed è soprattutto usato quando è necessario eseguire istruzioni particolari o specifiche del motore di database adottato.

Ti consigliamo anche