Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Usar SqlCommand para executar instruções Transact-SQL (T-SQL) ou procedimentos armazenados. Um comando precisa de um SqlConnection aberto. Descarte o comando após a utilização e descarte qualquer reader antes de reutilizar a conexão.
Os exemplos neste artigo assumem que uma connection aberta com o nome SqlConnection tem como alvo a base de dados de exemplo do AdventureWorks.
Os exemplos de C# requerem using Microsoft.Data.SqlClient;. Exemplos que usam SqlDbType, CommandType ou CommandBehavior também requerem using System.Data;.
Para a configuração, autenticação e encriptação da ligação, consulte Cadeias de ligação e Encriptação e validação de certificados.
Escolha um método de execução
Escolha o método que corresponde ao resultado esperado:
| Method | Utilizar quando | Result |
|---|---|---|
| ExecuteNonQuery | O comando altera dados ou esquema. | O número de linhas afetadas.
-1 pode ocorrer quando não há contagem disponível, incluindo quando SET NOCOUNT ON suprime contagens. |
| ExecuteScalar | Precisas de um valor. | A primeira coluna da primeira linha, ou null quando o resultado não tem linhas. Uma base de dados NULL é devolvida como Value. |
| ExecuteReader | Precisas de linhas, múltiplos conjuntos de resultados ou esquema. | Um SqlDataReader. |
| ExecuteXmlReader | O comando devolve XML na forma exigida por ExecuteXmlReader. |
Um XmlReader. |
Cada método tem um equivalente assíncrono baseado em tarefas. Passe a CancellationToken quando o chamador precisa de parar de esperar. Para o comportamento de cancelamento e timeout, veja Programação assíncrona.
Executar um comando de texto
CommandType.Text é o padrão. Coloque a instrução em CommandText e passe os valores através dos parâmetros:
const string sql = """
SELECT ProductID, Name, ListPrice
FROM Production.Product
WHERE ProductSubcategoryID = @subcategoryId
ORDER BY ListPrice DESC;
""";
using var command = new SqlCommand(sql, connection);
command.Parameters.Add("@subcategoryId", SqlDbType.Int).Value = 2;
using SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(
$"{reader.GetInt32(0)} | {reader.GetString(1)} | {reader.GetDecimal(2):C}");
}
Para tipos de parâmetros, tamanhos, valores nulos e direções, veja Configurar parâmetros. Não concatene valores não confiáveis a CommandText.
Executar um procedimento armazenado
Defina CommandType.StoredProcedure e use o nome do procedimento qualificado pelo esquema:
using var command = new SqlCommand(
"dbo.uspGetEmployeeManagers",
connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(
"@BusinessEntityID",
SqlDbType.Int).Value = 6;
using SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(
$"{reader.GetString(2)} {reader.GetString(3)}");
}
Microsoft. Data.SqlClient suporta CommandType.Text e CommandType.StoredProcedure. Definir CommandType.TableDirect gera ArgumentOutOfRangeException.
Verifique o que cada método devolve
Utilize ExecuteScalar quando precisar de um único valor:
using var command = new SqlCommand(
"SELECT COUNT(*) FROM Production.Product WHERE SellEndDate IS NULL;",
connection);
int currentProductCount = (int)command.ExecuteScalar()!;
Console.WriteLine($"Current products: {currentProductCount}");
ExecuteScalar retorna null quando o resultado não tem linhas e DBNull.Value quando o primeiro valor é um valor de base de dados NULL.
Utilize ExecuteNonQuery para instruções que alteram dados. Este exemplo reverte a sua alteração para que o AdventureWorks permaneça inalterado:
using SqlTransaction transaction = connection.BeginTransaction();
using var command = new SqlCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = @status
WHERE SalesOrderID = @salesOrderId;
""", connection, transaction);
command.Parameters.Add("@status", SqlDbType.TinyInt).Value = 2;
command.Parameters.Add("@salesOrderId", SqlDbType.Int).Value = 43659;
int rowsAffected = command.ExecuteNonQuery();
Console.WriteLine($"Rows affected: {rowsAffected}");
transaction.Rollback();
SET NOCOUNT ON suprime as contagens de linhas afetadas, podendo ExecuteNonQuery assim devolver -1 mesmo quando uma instrução altera os dados.
Utilize ExecuteXmlReader para um FOR XML resultado:
using var command = new SqlCommand("""
SELECT TOP (3) ProductID, Name
FROM Production.Product
ORDER BY ProductID
FOR XML PATH('Product'), ROOT('Products');
""", connection);
using System.Xml.XmlReader reader = command.ExecuteXmlReader();
reader.MoveToContent();
Console.WriteLine(reader.ReadOuterXml());
Utilize uma transação local
Quando uma ligação tem uma SqlTransaction local ativa, atribui essa transação a todos os comandos executados na ligação. Este exemplo reverte a sua alteração para que o AdventureWorks permaneça inalterado:
using SqlTransaction transaction = connection.BeginTransaction();
using var command = new SqlCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = @status
WHERE SalesOrderID = @salesOrderId;
""", connection, transaction);
command.Parameters.Add("@status", SqlDbType.TinyInt).Value = 2;
command.Parameters.Add("@salesOrderId", SqlDbType.Int).Value = 43659;
command.ExecuteNonQuery();
transaction.Rollback();
Clique Commit em vez de Rollback apenas quando a aplicação aceita a transação completa. Um comando que não faz referência à transação ativa lança InvalidOperationException. A execução também falha se a transação pertencer a outra conexão. Para limites de transações e rollback, veja Transações Locais.
Defina um tempo limite de comando
CommandTimeout limita os tempos de espera da execução de comandos e da leitura cumulativa da rede, em segundos. Um comando utiliza a configuração da Command Timeout ligação quando uma está configurada. Caso contrário, o padrão é 30 segundos. Um valor de 0 não tem limite de tempo. Valores negativos geram ArgumentException.
Quando o timeout expira, o comando lança SqlException com Number definido para -2:
using var command = new SqlCommand(
"WAITFOR DELAY '00:00:05';",
connection)
{
CommandTimeout = 1
};
try
{
command.ExecuteNonQuery();
}
catch (SqlException exception) when (exception.Number == -2)
{
Console.WriteLine("The command timed out.");
}
Connect Timeout Limita o estabelecimento de conexão e os tempos de espera do pool.
CommandTimeout começa após o início da execução do comando. Para mais informações, consulte Opções de ligação.
Utilize um timeout finito e um token de cancelamento em conjunto. O timeout define um limite para a operação da base de dados. Cancelar o token pode devolver o controlo ao chamador antes do timeout expirar. Não presuma que cancelamento e timeout produzem a mesma exceção.
Reutilizar e preparar comandos
Adicione um parâmetro uma vez e depois altere o seu valor após cada execução terminar:
using var command = new SqlCommand("""
SELECT TOP (1) Name, ListPrice
FROM Production.Product
WHERE ProductSubcategoryID = @subcategoryId
ORDER BY ListPrice DESC;
""", connection);
SqlParameter subcategoryId = command.Parameters.Add(
"@subcategoryId",
SqlDbType.Int);
foreach (int id in new[] { 1, 2, 3 })
{
subcategoryId.Value = id;
using SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
Console.WriteLine($"{id}: {reader.GetString(0)}");
}
}
Ligue Prepare apenas quando as medições o justifiquem.
Prepare Não prepara procedimentos armazenados ou comandos de texto sem parâmetros. Para texto parametrizado, defina metadados completos como Size, Scale e Prepare em cada parâmetro antes de chamar Precision.
Comandos de resolução de problemas
Utilize SqlException à volta da operação da base de dados e inspecione a sua coleção Errors quando o servidor devolver mais do que um erro. Para erros de comando, avisos e mensagens informativas, veja Gerir erros e mensagens.
Utilize contadores de diagnóstico, rastreio de fontes de eventos e o guia de resolução de problemas do SqlClient quando um erro requer mais contexto. Aplique lógica de retentativa configurável apenas quando repetir o comando for seguro.