Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Utilice SqlCommand para ejecutar instrucciones Transact-SQL (T-SQL) o procedimientos almacenados. Un comando necesita un SqlConnection abierto. Desecha el objeto Command después de usarlo y desecha cualquier objeto Reader antes de reutilizar la conexión.
Los ejemplos de este artículo dan por hecho que un SqlConnection abierto denominado connection apunta a la base de datos de ejemplo AdventureWorks.
Los ejemplos de C# requieren using Microsoft.Data.SqlClient;. Ejemplos que usan SqlDbType, CommandType o CommandBehavior también requieren using System.Data;.
Para establecer conexiones, autenticación y cifrado, consulte Cadenas de conexión y Cifrado y validación de certificados.
Elige un método de ejecución
Elige el método que coincida con el resultado esperado:
| Método | Se utiliza cuando | Resultado |
|---|---|---|
| ExecuteNonQuery | El comando cambia datos o esquema. | Número de filas afectadas.
-1 puede ocurrir cuando no hay recuento disponible, incluso cuando SET NOCOUNT ON suprime conteos. |
| ExecuteScalar | Necesitas un valor. | La primera columna de la primera fila, o null cuando el resultado no tiene filas. Una base de datos NULL se devuelve como Value. |
| ExecuteReader | Necesitas filas, varios conjuntos de resultados o esquema. | Un objeto SqlDataReader. |
| ExecuteXmlReader | El comando devuelve XML en la forma requerida por ExecuteXmlReader. |
Un valor de tipo XmlReader. |
Cada método tiene un equivalente asincrónico basado en tareas. Pase un CancellationToken cuando el llamante necesite dejar de esperar. Para el comportamiento de cancelación y tiempos de espera, véase Programación asíncrona.
Ejecutar un comando de texto
CommandType.Text es el valor predeterminado. Coloca la sentencia en CommandText y pasa los valores a través de los 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, tamaños, valores nulos y direcciones, consulte Configurar parámetros. No concatenes valores no confiables en CommandText.
Ejecución de un procedimiento almacenado
Establece CommandType.StoredProcedure y utiliza el nombre del procedimiento cualificado por el 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 soporta CommandType.Text y CommandType.StoredProcedure. Al establecer CommandType.TableDirect se produce una excepción ArgumentOutOfRangeException.
Comprueba qué devuelve cada método
Usa ExecuteScalar cuando necesites un 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 devuelve null cuando el resultado no tiene filas y DBNull.Value cuando el primer valor es una NULL de la base de datos.
Utilice ExecuteNonQuery para instrucciones que modifican datos. Este ejemplo revierte su cambio para que AdventureWorks permanezca sin cambios:
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 los conteos de filas afectadas, por lo que ExecuteNonQuery puede devolver -1 incluso cuando una instrucción cambia datos.
Usa ExecuteXmlReader para un 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());
Utiliza una transacción local
Cuando una conexión tiene un SqlTransaction local activo, asigne esa transacción a cada comando ejecutado en la conexión. Este ejemplo revierte su cambio para que AdventureWorks permanezca sin cambios:
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();
Llama Commit en vez de Rollback solo cuando la aplicación acepta la transacción completa. Un comando que no hace referencia a la transacción activa lanza InvalidOperationException. La ejecución también falla si la transacción pertenece a otra conexión. Para los límites de transacción y el rollback, véase Transacciones locales.
Establecer un tiempo de espera de comando
CommandTimeout limita la ejecución de comandos y las esperas acumuladas de lectura de red en segundos. Un comando utiliza la configuración de Command Timeout de la conexión cuando hay alguna configurada. Si no, el valor por defecto son 30 segundos. Un valor de 0 no tiene límite de tiempo. Los valores negativos lanzan una excepción ArgumentException.
Cuando expira el tiempo de espera, el comando lanza SqlException con Number fijado en -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 el establecimiento de conexiones y las esperas del grupo de conexiones.
CommandTimeout se inicia después de que comienza la ejecución del comando. Para más información, consulte Opciones de conexión.
Usa un tiempo límite de espera y un token de cancelación juntos. El tiempo de espera establece un límite en la operación de la base de datos. Cancelar el token puede devolver el control al llamante antes de que expire el tiempo de espera. No des por hecho que la cancelación y el tiempo de espera producen la misma excepción.
Reutilizar y preparar comandos
Añade un parámetro una vez y luego cambia su valor una vez finalizada cada ejecución:
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)}");
}
}
Llama Prepare solo cuando las medidas lo justifiquen.
Prepare No prepara procedimientos almacenados ni comandos de texto sin parámetros. Para texto parametrizado, establece metadatos completos como Size, Scale y Prepare en cada parámetro antes de llamar a Precision.
Comandos para solucionar problemas
Captura SqlException en torno a la operación de la base de datos e inspecciona su Errors colección cuando el servidor devuelva más de un error. Para errores de comando, advertencias e mensajes informativos, véase Manejar errores y mensajes.
Utiliza contadores de diagnóstico, rastreo de fuentes de eventos y la guía de solución de problemas de SqlClient cuando un error requiera más contexto. Aplica lógica de reintento configurable solo cuando repetir el comando sea seguro.