C# ADO.NET: Chamada de procedimentos armazenados e SqlDataReader
Chamar procedimentos armazenados do SQL Server e ler resultados em fluxo com SqlDataReader, pontos fundamentais:
SqlCommand.CommandType = CommandType.StoredProceduredefine que um procedimento armazenado será executado- Passar parâmetros para o procedimento armazenado usando
SqlParameter ExecuteReader(CommandBehavior.CloseConnection)para ler o fluxo de dados- SqlDataReader é um leitor somente leitura, de avanço sequencial e baseado em fluxo e deve ser fechado após o uso
Definição do procedimento armazenado
Você precisa criar o procedimento armazenado previamente no banco de dados antes de chamá‑lo.
create proc myProc
@id int
as
select * from [dbo].[Article] where id>@id
go
-- Teste de chamada
exec myProc @id=5Code language: JavaScript (javascript)
Recebe o parâmetro @id e retorna registros da tabela Article onde o id seja maior que o valor informado.
Chamar procedimentos armazenados em C#
ExecuteReader retorna um SqlDataReader para obter várias linhas de dados.
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());
}Code language: C# (cs)
Liberar o Reader com using para evitar vazamento 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;//informa que o comando é um procedimento armazenado
// adicionar parâmetro de entrada
sqlCom.Parameters.Add("@id", SqlDbType.Int).Value = 4;
// CommandBehavior.CloseConnection: fecha a conexão automaticamente quando o reader for fechado
using (SqlDataReader reader = sqlCom.ExecuteReader(CommandBehavior.CloseConnection))
{
StringBuilder sb = new StringBuilder();
while (reader.Read())
{
// reader[0] primeira coluna, reader[1] segunda coluna; também aceita reader["NomeDaColuna"]
sb.AppendLine($"{reader[0]}-{reader[1]}");
}
MessageBox.Show(sb.ToString());
}
// Não é necessário chamar reader.Close() manualmente, o using cuida da liberação automática
}
}Code language: C# (cs)
Os três valores de enumeração CommandType
CommandType.Text: executar instruções SQL comunsCommandType.StoredProcedure: executar procedimento armazenadoCommandType.TableDirect: ler diretamente uma tabela do banco
Se você não definir
StoredProcedure, o programa interpretará o nome do procedimento como uma instrução SQL normal e lançará um erro!
Direções de parâmetro do SqlParameter
ParameterDirection.Input: parâmetro de entrada (recebe valor, mais utilizado)ParameterDirection.Output: parâmetro de saídaParameterDirection.InputOutput: parâmetro bidirecional entrada‑saídaParameterDirection.ReturnValue: valor retornado pelo procedimento armazenado
O que faz CommandBehavior.CloseConnection
Quando SqlDataReader chamar Close() ou for liberado, a SqlConnection associada será fechada automaticamente.
Cenário ideal: quando um método retorna um objeto Reader, a conexão é recuperada após o código externo terminar a leitura dos dados.
Características importantes do SqlDataReader
- Somente leitura e avanço sequencial: só percorre registros para frente com
Read(), não permite voltar nem alterar dados - Mantém a conexão ocupada: enquanto o Reader estiver aberto, a conexão com o banco não pode executar outras operações
- Recursos devem ser liberados: chame
reader.Close()manualmente ou prefira a liberação automática comusing - Duas formas de ler colunas:
csharp reader[0]; // leitura por índice reader["Title"]; // leitura por nome do campo (melhor legibilidade)
Avisos importantes
- Esquecer de configurar
CommandType.StoredProcedure→ falha na execução - Nomes de parâmetros com diferença de letras maiúsculas/minúsculas ou grafia diferente do procedimento armazenado → parâmetros não correspondem
- Reader não fechado → conexão permanece ocupada e esgota o pool de conexões
- Executar novas consultas dentro de
while(reader.Read()): uma mesma conexão não suporta múltiplos leitores ativos ao mesmo tempo - Parâmetros faltantes ou tipos incompatíveis no procedimento armazenado → erro em tempo de execução
Comparação
| Método de execução | Cenário de uso | Objeto retornado |
|---|---|---|
| ExecuteNonQuery | Procedimentos armazenados para inserir, atualizar e excluir | int linhas afetadas |
| ExecuteScalar | Retornar uma única linha e coluna (consultas de agregação) | object |
| ExecuteReader | Retornar conjuntos de dados com várias linhas | SqlDataReader (leitura em fluxo) |
SqlDataReader