C# ADO.NET: Llamada a procedimientos almacenados y SqlDataReader
Llamar procedimientos almacenados de SQL Server y leer resultados mediante flujo con SqlDataReader, puntos clave:
SqlCommand.CommandType = CommandType.StoredProceduremarca que se ejecutará un procedimiento almacenado- Pasar parámetros al procedimiento almacenado usando
SqlParameter ExecuteReader(CommandBehavior.CloseConnection)para leer el flujo de datos- SqlDataReader es un lector solo lectura y de avance secuencial basado en flujo que debe cerrarse después de usarlo
Definición del procedimiento almacenado
Debes crear previamente el procedimiento almacenado en la base de datos para poder invocarlo.
create proc myProc
@id int
as
select * from [dbo].[Article] where id>@id
go
-- Prueba de llamada
exec myProc @id=5Lenguaje del código: JavaScript (javascript)
Recibe el parámetro @id y devuelve registros de la tabla Article donde el valor de id sea mayor al valor recibido.
Llamar procedimientos almacenados desde C#
ExecuteReader devuelve un objeto SqlDataReader para leer múltiples filas de datos.
string connectionString = "Data Source=.;Initial Catalog=db;Integrated Security=SSPI;";
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand sqlCom = new SqlCommand();
sqlCom.Connection = conn;
sqlCom.CommandText = "myProc";
sqlCom.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("@id", SqlDbType.Int, 8);
param.Value = 4;
param.Direction = ParameterDirection.Input;
sqlCom.Parameters.Add(param);
SqlDataReader reader = sqlCom.ExecuteReader(CommandBehavior.CloseConnection);
StringBuilder sb = new StringBuilder();
while (reader.Read())
{
sb.AppendLine(reader[0] + "-" + reader[1]);
}
reader.Close();
MessageBox.Show(sb.ToString());
}Lenguaje del código: C# (cs)
Liberar el Reader con using para evitar fugas de recursos
string connectionString = "Data Source=.;Initial Catalog=db;Integrated Security=SSPI;";
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand sqlCom = new SqlCommand("myProc", conn))
{
sqlCom.CommandType = CommandType.StoredProcedure;//indica que el comando es un procedimiento almacenado
// agregar parámetro de entrada
sqlCom.Parameters.Add("@id", SqlDbType.Int).Value = 4;
// CommandBehavior.CloseConnection: cierra automáticamente la conexión al cerrar el reader
using (SqlDataReader reader = sqlCom.ExecuteReader(CommandBehavior.CloseConnection))
{
StringBuilder sb = new StringBuilder();
while (reader.Read())
{
// reader[0] primera columna, reader[1] segunda columna; también se puede usar reader["NombreColumna"]
sb.AppendLine($"{reader[0]}-{reader[1]}");
}
MessageBox.Show(sb.ToString());
}
// No hace falta llamar manualmente a reader.Close(), using libera los recursos automáticamente
}
}Lenguaje del código: C# (cs)
Los tres valores de enumeración de CommandType
CommandType.Text: ejecutar sentencias SQL normalesCommandType.StoredProcedure: ejecutar procedimiento almacenadoCommandType.TableDirect: leer directamente una tabla de base de datos
Si no configuras
StoredProcedure, el programa interpreta el nombre del procedimiento como una sentencia SQL común y lanzará un error.
Direcciones de parámetro en SqlParameter
ParameterDirection.Input: parámetro de entrada (pasar valores, el más usado)ParameterDirection.Output: parámetro de salidaParameterDirection.InputOutput: parámetro bidireccional entrada‑salidaParameterDirection.ReturnValue: valor devuelto por el procedimiento almacenado
Funcionamiento de CommandBehavior.CloseConnection
Cuando se invoca Close() o se libera el objeto SqlDataReader, se cierra automáticamente el SqlConnection asociado.
Escenario útil: cuando un método devuelve un objeto Reader, la conexión se recupera automáticamente una vez que el código externo termina de leer los datos.
Características importantes de SqlDataReader
- Solo lectura y avance secuencial: solo se puede avanzar con
Read(), no retroceder ni modificar registros - Ocupa la conexión: mientras el Reader esté abierto, la conexión de base de datos no puede ejecutar otras operaciones
- Es obligatorio liberar recursos: llamar manualmente a
reader.Close()o usar preferiblementeusingpara liberación automática - Dos formas de leer columnas:
csharp reader[0]; // lectura por índice reader["Title"]; // lectura por nombre de campo (más legible)
Advertencias
- Olvidar configurar
CommandType.StoredProcedure→ error de ejecución - Mayúsculas, minúsculas o escritura incorrecta en nombres de parámetros respecto al procedimiento almacenado → fallo de coincidencia
- No cerrar el Reader → la conexión permanece ocupada y se agota el grupo de conexiones
- Ejecutar nuevas consultas dentro de
while(reader.Read()): una misma conexión no admite varios lectores activos al mismo tiempo - Falta de parámetros o tipos incompatibles en el procedimiento almacenado → error en tiempo de ejecución
Comparación
| Método de ejecución | Casos de uso | Objeto devuelto |
|---|---|---|
| ExecuteNonQuery | Procedimientos almacenados para insertar, actualizar y eliminar | int filas afectadas |
| ExecuteScalar | Devolver una sola fila y una sola columna (consultas de agregación) | object |
| ExecuteReader | Devolver conjuntos de datos de varias filas | SqlDataReader (lectura por flujo) |
SqlDataReader