Molto spesso mi capita di dover lavorare su progetti realizzati in .Net 2.0 in cui viene fatto largo uso del namespace System.Data.SqlClient, è sempre molto spesso mi capita di incontrare un problema molto antipatico di cui dimentico puntualmente la soluzione!

Il problema è questo: supponiamo di voler implementare la chiamata ad una Stored Procedure il cui compito è:

  • restituire un elenco di risultati
  • restituire dei valori in output

La Stored Procedure accetta in input N parametri e restituisce in output altri M parametri. Per l’esempio che voglio proporvi ne utilizzeremo uno che si chiama @RowCount. Nella maggior parte dei casi viene commesso un errore logico durante la scrittura del codice:

//...
command = DataFactory.GetProcedure(SearchProcedure);
command.Parameters.Add("@RowCount", SqlDbType.Int, 4).Direction = ParameterDirection.Output;
DataFactory.OpenConnection();		

reader = command.ExecuteReader();
// L'errore che commettiamo è qui:
pi.RowCount = (int)command.Parameters["@RowCount"].Value;

//...

Cosa succede? In questa porzione di codice vengono effettuate diverse operazioni:

  • Viene inizializzato un comando
  • Viene specificato un parametro in output che dovrà essere valorizzato nella stored procedure e restituito nella variabile di output
  • Viene eseguita la query ed il risultato viene caricato in un SqlDataReader
  • Viene prelevato il valore del parametro in output

Il problema si può verificare a partire dalla descrizione specificata in grassetto (nell’elenco) e si verifica proprio se eseguiamo il passo successivo.

In pratica non è possibile prelevare dei valori in output ad una stored procedure, tramite un SqlCommand, se alla connessione è associato un SqlDataReader aperto, fin quando non invochiamo il metodo Close() dell’oggetto reader, le variabili in output della SqlParameterCollection non vengono caricate, motivo per cui la porzione di codice sopra mostrata genera un eccezione in riferimento al fatto che il .Value è NULL. Se invece proviamo a modificare il codice inserendo un reader.Close() prima di prelevare i valori in output, il tutto funziona correttamente!

Per informazioni più dettagliate sull’argomento potete cliccare qui. Nello specifico la frase che più ci interessa (e che mi salva la vita ogni volta) è questa:

If your Command contains output parameters or return values, they will not be available until the DataReader is closed.