Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea è quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

[MCAD.23] SqlConnection e SqlCommand: primi passi con ADO.NET

Nel post precedente, abbiamo creato un nuovo Windows Form per regalare alla nostra applicazione qualche funzionalità in più in materia di database, per esplorare per bene quello che ci offre ADO.NET. Il form è quello riportato qui sotto, tutti i dettagli sulla sua implementazione sono nel post [MCAD.22].

Quello che voglio fare oggi è la stessa cosa che ho anticipato la volta scorsa. Appena l'utente clicca sul pulsante Ok, vuol dire che desidera da questo momento utilizzare la nuova stringa di connessione specificata nella TextBox. Prima di farlo, però, vorrei controllare che 1) la connessione funzioni realmente e 2) esista la tabella ListBirthdays. Vogliamo, quindi, nell'ordine:

  1. testare la connessione al server, usando SqlConnection
  2. se la connessione funziona, verificare la presenza della tabella ListBirthdays
  3. se la tabella esiste, tutto ok, la form può essere chiusa senza problemi
  4. se la tabella non esiste, occorre lanciare la stored-procedure SettingUp che provvede a creare la tabella ListBirthdays
  5. se tutto fila liscio, la form può essere chiusa

Come lo facciamo? Beh, innanzitutto creiamo una function checkTable():

private bool CheckTable()
{ }

Questa function ritorna un bool (true = la tabella esiste oppure è stata creata, false = la connessione non funziona oppure qualche altra condizione di errore). In questa release ho deciso di lavorare soltanto con SQL Server, per cui useremo la classe SqlConnection :

// estratto di codice
if (this.TypeDB == SupportedTypeDB.SQLSERVER)
{
    
// la funzione ritorna
    // false: errore durante il controllo di esistenza della tabella
    // true: la tabella esiste oppure è stata creata con successo

    // mi connetto al db
    
SqlConnection conn = new SqlConnection(this.DBConnection);
    
// creo un Command per fare una semplice SELECT
    
SqlCommand cmd = new SqlCommand("SELECT id FROM ListBirthdays", conn);
    
// cmd.Connection = conn;
    //cmd.CommandType = CommandType.TableDirect;
    
cmd.CommandType = CommandType.Text;
    cmd.CommandTimeout = 15;

Come si vede, istanzio un oggetto conn di tipo SqlConnection. Il costruttore prende come parametro la stringa di connessione dalla property DBConnection (in alternativa, possiamo direttamente leggere this.txtDBConnection.Text). Successivamente, istanzio un SqlCommand cmd, facendo una semplice SELECT sulla tabella ListBirthdays. La classe SqlCommand ha diverse property: io mi sono divertito a dare un timeout per l'esecuzione del comando (CommandTimeOut) e il tipo di comando, specificato dall'enum CommandType.

Notare che al momento della creazione dell'oggetto SqlConnection, la connessione non viene aperta: lo facciamo noi manualmente nelle righe di codice successiva. Ovvero:

// apro la connessione
try { conn.Open(); }
catch return(false); }

// tengo di eseguire il comando
try { cmd.ExecuteScalar(); }
catch { errore = true; }

Tento di aprire la connessione: ho incluso il tutto in un blocco try...catch: se ci sono problemi, l'errore viene trappato, la function ritorna false come abbiamo detto prima. Se la connessione è ok, tento di eseguire il command che abbiamo predisposto prima: un altro blocco try...catch. Qui ho banalizzato un po' troppo: se ci sono problemi nell'eseguire il SqlCommand, invece di ritornare false, decido di gestire autonomamente la questione: parto dal presupposto che l'unico problema è che la tabella non esiste, quindi lancio la stored-procedure SettingUp. Quindi, vediamo il codice:

if (errore == true)
{
    
// in caso di errore, eseguo la sp SettingUp
    
cmd = new SqlCommand("SettingUp", conn);
    cmd.CommandType = CommandType.StoredProcedure;
    
try { cmd.ExecuteReader(); }
    
catch return(false); }
}

Preparo un SqlCommand nuovo, usando cmd. Questa volta si tratta di una sp (notare la property CommandType) chiamata, appunto, SettingUp. Ho messo un altro blocco try...catch: se anche questa volta ho un errore di qualsiasi tipo, ritorno false al chiamante. Le ultime linee di codice chiudono la connessione, rilasciano le risorse. Poi, se tutto è andato per il verso giusto, ritorno true.

// chiudo la connessione
conn.Close();
// rilascio le risorse
cmd.Dispose();
conn.Dispose();

Questo riportato sopra a "pezzi di codice" è la function checkTable() che viene eseguita quando l'utente clicca sul Button Ok del form frmConnection. Il suo handler è il seguente:

private void btnOk_Click(object sender, System.EventArgs e)
{
    
if (!CheckTable())
        MessageBox.Show(
this, "Errore durante il controllo della struttura del database!",
            "Errore!", MessageBoxButtons.OK, MessageBoxIcon.Error);
    
this.Close();
}

Semplicemente, se la function ritorna false, mostro una MessageBox all'utente dicendo che non siamo riusciti a verificare la struttura del database (inteso sia come connessione, sia come struttura: tabella e/o stored-procedure). La stored-procedure SettingUp, di cui non abbiamo parlato, è semplicemente un'istruzione CREATE TABLE ListBirthdays che genera i campi id, name e birthday.

Comment e miglioramenti del codice
Nel post di ieri, ho ricevuto un comment da parte di Igor (che non sono io!) che mi ha proposto due miglioramenti del codice che ho scritto. Mi sono sembrate entrambe cose piuttosto interessanti, per cui ho deciso in 2 secondi di integrarle.

La prima è l'utilizzo di un enum SupportedTypeDB per gestire Access e SQL Server al posto delle stringhe. Il codiceif (this.TypeDB == SupportedTypeDB.SQLSERVER) utilizza proprio questo enum invece di una banale string "SQLSERVER". Il codice è quindi cambiato di conseguenza: get/set della property, lettura da app.config, etc. Come ho fatto a creare un enum globale? Ho fatto Add --> New Item --> Code File: il file l'ho chiamato GeneralCode.cs e a questo punto ho scritto il codice:

public enum SupportedTypeDB
{
    ACCESS = 0,
    SQLSERVER = 1
}

La seconda modifica è spiegata direttamente nel comment di Igor e nella mia contro-risposta. Invece di creare un oggetto AppSettingsReader, scrivo direttamente ConfigurationSettings.AppSettings["key"] per accedere velocemente agli elementi del file app.config. Comodo, veloce e più simpatico!

powered by IMHO 1.2

Print | posted on giovedì 25 agosto 2005 20:27 | Filed Under [ MCAD ]

Feedback

Gravatar

# re: [MCAD.23] SqlConnection e SqlCommand: primi passi con ADO.NET

Complimenti Igor per i tuoi post che stanno dando una guida molto chiara a chi intende prepararsi per l'esame di certificazione.
Volevo darti solo un piccolo suggerimento sul codice, non tanto perché non funzioni, ma perché oltre a risultare più pulito il codice, una finezza del genere potrebbe costarti un errore nell'esame di certificazione:
Nell'eseguire una SP che altera la struttura del database sarebbe meglio utilizzare il metodo ExecuteNonQuery invece di ExecuteReader.
26/08/2005 12:20 | Daniele Proietti
Gravatar

# [MCAD.24] Alcuni miglioramenti del codice

26/08/2005 17:38 | Technology Experience
Gravatar

# [MCAD.25] Esportazione dei dati su database: SqlConnection, SqlDataAdapter e SqlCommand

29/08/2005 16:13 | Technology Experience
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET