Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2764, trackbacks - 17617

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 17.27 | Filed Under [ MCAD ]

Feedback

Gravatar

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

Ciao Igor,
innanzitutto grazie per le citazioni ...
mi permetto ancora una volta di fare il pignolo: spero tu non la prenda a male...e' un modo per confrontarci e migliorarci...se le mie osservazioni dovessero essere castronerie,avremo imparato in 2 :).
Allora, inizio:
a) Dallo scorcio di stringa di connessione che vedo, noto che usi la security integrata per accedere a sql server ... personalmente preferisco sempre quella proprietaria per vari motivi: maggiore isolamento tra UI layer e Data Layer, maggiore security (non devo creare account/dare permission ad utenti censiti su un'altra macchina/dominio).
Di solito creo un login (proprietario,su SQL Server) e gli do i diritti di dbowner sul db al quale accedera' (e che sara' il suo default DB). Quell'utente potra' accedere SOLO a quel DB e non potra' fare danni in giro.
Capisco anche che sono articoli che mirano alla comprensione del codice...e per questo sei perdonato :).

b) Gli Enum della connessione (che hai specificato in statements separati) puoi specificarli anche nel costruttore...de gustibus...

c) Se hai deciso di rendere il programmino dipendente da SP (cosa che potrebbe essere opinabile in ambienti nei quali si prevede la portabilita' su piu' piattaforme DB come Oracle), perche' non ne fai una che controlla che ci sia tutto sul DB (e ti restituisca 0 se ti va tutto OK o il numero dell'errore che poi mapperai nell'applicativo) ?
Ok ok ... volevi mostrare la gestione strutturata delle eccezioni :)...pardon :P.

d) Nell'app.config hai sostituito la stringa al valore 0 o 1 per la chiave relativa al SupportedDBType, vero ?

Spero di non essere sembrato troppo spavaldo nelle considerazioni sul tuo codice...

Happy Coding,
Igor.
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 9.20 | Daniele Proietti
Gravatar

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

rispondo a tutti e due!
Innanzitutto sappiate che mi fa molto piacere ricevere i vostri comment: sono ASSOLUTAMENTE COSTRUTTIVI, per cui non abbia timore a correggermi e a migliorare il mio codice. Lo scopo della mia serie di post su MCAD non è solo rendere pubblico il mio studio, è anche e soprattutto confrontarmi con gli altri. Con i vostri comment e i vostri suggerimenti, potrò (potremo) scrivere codice molto, molto migliore, tutti insieme!!! :-)

Inizio con i comment di Igor...
a) in breve, intendi creare uno user di Windows invece di uno user di SQL Server, giusto? Non capisco come migliora il "maggiore isolamento tra UI layer e Data Layer" usando questo metodo di accesso...cosa cambia esattamente?
b) ehm, cosa intendi? mi fai un esempietto? vorrei fare come dici tu, ma non ho capito...
c) assolutamente d'accordo
d) assolutamente SI'

Rispondo anche a Daniele!
Ottimo suggerimento: ExecuteNonQuery() ritorna il numero di affected rows, -1 nel caso di command come appunto l'esecuzione di una sp che non ritorna nulla. Modificherò il codice!!
26/08/2005 9.47 | Igor Damiani
Gravatar

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

Ciao Igor...rieccomi a correggere i miei punti :)
a) Dallo scorcio di stringa di connessione che leggo dagli screenshot, c'e' la clausola "Integrated Security..."; questo mi fa pensare che non utilizzi la security di SQL ma quella integrata di Windows...sbaglio ?

b) Attualmente, come deserializzi il TypeDB dall'app.config ? Suppongo che, per poter confrontare l'enum (SupportedDBType) con la property (TypeDB) questi siano dello stesso tipo (int) ... ergo mi chiedevo se, appunto, nell'attributo value tu avessi lasciato la stringa (SQLSERVER o ACCESS) oppure 0 e 1 ... tutto qui ... <add key="TypeDB" value=""/> .

Continua cosi' con gli articoli... :)
Igor.
Gravatar

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

a) no, non ho usato un utente Windows. Ho creato uno user 'age_user' in SQL Server, a cui ho dato l'accesso solo al db 'age'. Francamente, non so cosa indichi la clausola 'Integrated Security' nella string connection.
b) sì sì, certo. nel file app.config TypeDB adesso è 1. Leggo dal file usando AppSettings (che ritorna un string), converto in int e facendo infine un cast a SupportedTypeDB.

Però la mia domanda era riferita al fatto di mettere nel costruttore l'enum...cosa intendi?
26/08/2005 11.05 | Igor Damiani
Gravatar

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

Scusami...ho sbagliato punto al quale rispondere...
mi sono confuso con un altro costruttore (sorry :P): ignora quel punto :).

Igor.
Gravatar

# [MCAD.24] Alcuni miglioramenti del codice

26/08/2005 14.38 | Technology Experience
Gravatar

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

29/08/2005 13.13 | Technology Experience
Gravatar

# doa32jk6

doa32jk6 &lt;a href='http://buy-phentermine-with-mastercard.tangoing.info/'&gt;buy phentermine with mastercard&lt;/a&gt; http://buy-phentermine-with-mastercard.tangoing.info/ &lt;a href=&quot;http://buy-phentermine-with-mastercard.tangoing.info/ &quot;&gt;buy phentermine with mastercard&lt;/a&gt;
12/12/2007 9.32 | doa32jk6
Gravatar

# Acyclovir.

Acyclovir picture. Acyclovir and poison ivy. Acyclovir side effects. Acyclovir. Using acyclovir for treatment of poison ivy.
30/03/2009 15.02 | Acyclovir.
Gravatar

# Paxil cr.

Paxil withdrawal. Paxil side effects. How long will it take paxil to leave the body. Paxil. Paxil withdrawal and skin irritations. What is paxil.
09/04/2009 16.54 | Paxil withdrawal.
Gravatar

# Comment levitra.

Viagra cialis levitra buy cheap cialis buy ciali. Cialis viagra levitra. Levitra.
15/04/2009 20.25 | Levitra.
Comments have been closed on this topic.

Powered by: