Configuración de parámetros
Se aplica a: .NET Framework .NET .NET Standard
Los objetos de comando usan parámetros para pasar valores a instrucciones SQL o procedimientos almacenados que permiten realizar operaciones de comprobación de tipos y validación. A diferencia del texto de comando, la entrada de parámetros se trata como un valor literal, y no como código ejecutable. Este comportamiento ayuda a protegerse contra ataques por "inyección de código SQL", en los que un atacante inserta un comando en una instrucción SQL que pone en peligro la seguridad del servidor.
Los comandos parametrizados también pueden mejorar el rendimiento de ejecución de la consulta, ya que ayudan al servidor de bases de datos a que haga coincidir precisamente el comando entrante con un plan de consulta almacenado en caché adecuado. Para obtener más información, consulte Almacenar en caché y volver a utilizar un plan de ejecución y Parámetros y reutilización de un plan de ejecución. Además de las ventajas en la seguridad y el rendimiento, los comandos con parámetros proporcionan un método práctico para organizar los valores que se pasan a un origen de datos.
Para crear un objeto DbParameter , se puede usar su constructor o bien se puede agregar a DbParameterCollection mediante una llamada al método Add
de la colección DbParameterCollection . El método Add
acepta como entrada argumentos del constructor o cualquier objeto de parámetro ya existente, en función del proveedor de datos.
Provisión de la propiedad ParameterDirection
Cuando se agregan parámetros distintos de los parámetros de entrada, se debe proporcionar una propiedad ParameterDirection . En la tabla siguiente se muestran los valores de ParameterDirection
que se pueden usar con la enumeración ParameterDirection .
Nombre del miembro | Descripción |
---|---|
Input | Se trata de un parámetro de entrada. Este es el valor predeterminado. |
InputOutput | El parámetro se puede comportar tanto de entrada como de salida. |
Output | Se trata de un parámetro de salida. |
ReturnValue | El parámetro representa un valor devuelto de una operación como, por ejemplo, un procedimiento almacenado, una función integrada o una función definida por el usuario. |
Trabajo con marcadores de posición de parámetros
La sintaxis de los marcadores de posición de parámetros depende del origen de datos. El proveedor de datos SqlClient de Microsoft para SQL Server controla la asignación de nombres y la especificación de parámetros y marcadores de posición de parámetros de forma diferente. El proveedor de datos SqlClient usa parámetros con nombre con el formato @parametername
.
Especificación de tipos de datos de parámetro
El tipo de datos de un parámetro es específico del proveedor de datos SqlClient de Microsoft para SQL Server. Al especificar el tipo, el valor de Parameter
se convierte en el tipo de proveedor de datos SqlClient de Microsoft para SQL Server antes de pasar el valor al origen de datos. Si lo desea, puede especificar el tipo de un objeto Parameter
de forma genérica estableciendo la propiedad DbType
del objeto Parameter
en un DbTypedeterminado.
El tipo de proveedor de datos SqlClient de Microsoft para SQL Server de un objeto Parameter
se deduce del tipo .NET Framework de Value
del objeto Parameter
, o de DbType
del objeto Parameter
. En la siguiente tabla se muestra el tipo deducido de Parameter
en función del objeto que se ha pasado como valor Parameter
o del DbType
especificado.
Tipo de .NET | DbType | SqlDbType |
---|---|---|
Boolean | Boolean |
Bit |
Byte | Byte |
TinyInt |
byte[] |
Binary |
VarBinary . Esta conversión implícita generará un error en el caso de que la matriz de bytes tenga un tamaño superior al tamaño máximo de un tipo VarBinary , que es de 8000 bytes. En matrices de bytes con más de 8000 bytes, establezca de forma explícita el tipo SqlDbType. |
Char | No se admite la inferencia de un SqlDbType de char. | |
DateTime | DateTime |
DateTime |
DateTimeOffset | DateTimeOffset |
DateTimeOffset en SQL Server 2008. No se admite la inferencia de un SqlDbType de DateTimeOffset en versiones de SQL Server anteriores a SQL Server 2008. |
Decimal | Decimal |
Decimal |
Double | Double |
Float |
Single | Single |
Real |
Guid | Guid |
UniqueIdentifier |
Int16 | Int16 |
SmallInt |
Int32 | Int32 |
Int |
Int64 | Int64 |
BigInt |
Object | Object |
Variant |
String | String |
NVarChar . Esta conversión implícita generará un error en el caso de que la cadena tenga un tamaño superior al tamaño máximo de un tipo NVarChar , que es de 4000 bytes. En cadenas con más de 4.000 caracteres, establezca de forma explícita el tipo SqlDbType. |
TimeSpan | Time |
Time en SQL Server 2008. No se admite la inferencia de un SqlDbType de TimeSpan en versiones de SQL Server anteriores a SQL Server 2008. |
UInt16 | UInt16 |
No se admite la inferencia de un SqlDbType de UInt16 . |
UInt32 | UInt32 |
No se admite la inferencia de un SqlDbType de UInt32 . |
UInt64 | UInt64 |
No se admite la inferencia de un SqlDbType de UInt64 . |
AnsiString |
VarChar |
|
AnsiStringFixedLength |
Char |
|
Currency |
Money |
|
Date |
Date en SQL Server 2008. No se admite la inferencia de un SqlDbType de Date en versiones de SQL Server anteriores a SQL Server 2008. |
|
SByte |
No se admite la inferencia de un SqlDbType de SByte . |
|
StringFixedLength |
NChar |
|
Time |
Time en SQL Server 2008. No se admite la inferencia de un SqlDbType de Time en versiones de SQL Server anteriores a SQL Server 2008. |
|
VarNumeric |
No se admite la inferencia de un SqlDbType de VarNumeric . |
|
tipo definido por el usuario (un objeto con SqlUserDefinedAggregateAttribute | SqlClient siempre devuelve un objeto | SqlDbType.Udt si SqlUserDefinedTypeAttribute está presente; de lo contrario, Variant . |
Nota
Las conversiones de valores de tipo decimal en otros tipos de valor son conversiones de restricción que redondean el valor decimal al valor entero más próximo a cero. Si el resultado de la conversión no se puede representar en el tipo de destino, se produce una OverflowException.
Nota
Cuando se envía un valor de parámetro nulo al servidor, se debe especificar DBNull, no null
(Nothing
en Visual Basic). El valor nulo en el sistema es un objeto vacío que no tiene ningún valor. Para representar los valores nulos, se usaDBNull .
Derivación de información de parámetro
Los parámetros también se pueden derivar de un procedimiento almacenado mediante la clase DbCommandBuilder
. La clase SqlCommandBuilder
proporciona un método estático, DeriveParameters
, que rellena automáticamente la colección de parámetros de un objeto de comando que usa información de parámetros de un procedimiento almacenado. Tenga en cuenta que DeriveParameters
sobrescribirá toda la información de parámetros existente en el comando.
Nota
La derivación de información de parámetros afecta al rendimiento, ya que precisa un viaje adicional de ida y vuelta (round trip) al origen de datos para recuperar la información. Si la información de los parámetros se conoce en tiempo de diseño, se puede mejorar el rendimiento de la aplicación si se establecen los parámetros con los valores correspondientes de forma explícita.
Para obtener más información, vea Generar comandos con objetos CommandBuilder.
Uso de parámetros con SqlCommand y un procedimiento almacenado
Los procedimientos almacenados ofrecen numerosas ventajas en el caso de aplicaciones que procesan datos. Mediante el uso de procedimientos almacenados, las operaciones de base de datos se pueden encapsular en un solo comando, optimizarse para obtener el mejor rendimiento y mejorarse con seguridad adicional. Aunque es cierto que para llamar a un procedimiento almacenado basta con pasar en forma de instrucción SQL su nombre seguido de los argumentos de parámetros, el uso de la colección Parameters del objeto DbCommand de ADO.NET permite definir más explícitamente los parámetros del procedimiento almacenado, y tener acceso a los parámetros de salida y a los valores devueltos.
Nota
Las instrucciones con parámetros se ejecutan en el servidor utilizando sp_executesql,
; esto permite volver a utilizar el plan de consultas. Los cursores o las variables locales del lote de sp_executesql
no son visibles para el lote que llama a sp_executesql
. Los cambios en el contexto de base de datos solo se mantienen hasta el final de la instrucción sp_executesql
. Para más información, consulte sp_executesql (Transact-SQL).
Cuando se usan parámetros con SqlCommand para ejecutar un procedimiento almacenado de SQL Server, los nombres de los parámetros agregados a la colección Parameters deben coincidir con los nombres de los marcadores de parámetro del procedimiento almacenado. El proveedor de datos Microsoft SqlClient para SQL Server no admite el marcador de posición de signo de interrogación (?) para pasar parámetros a una instrucción SQL o a un procedimiento almacenado. Este proveedor trata los parámetros del procedimiento almacenado como parámetros con nombre y busca marcadores de parámetros coincidentes. Por ejemplo, el procedimiento almacenado CustOrderHist
se define usando un parámetro denominado @CustomerID
. Cuando el código ejecuta el procedimiento almacenado, también debe usar un parámetro denominado @CustomerID
.
CREATE PROCEDURE dbo.CustOrderHist @CustomerID varchar(5)
Ejemplo
En este ejemplo se muestra cómo llamar a un procedimiento almacenado de SQL Server en la base de datos de ejemplo Northwind
. El nombre del procedimiento almacenado es dbo.SalesByCategory
e incluye un parámetro de entrada denominado @CategoryName
con el tipo de datos nvarchar(15)
. El código crea una nueva clase SqlConnection dentro de un bloque en uso, de forma que la conexión se cierre cuando finalice el procedimiento. Se crean los objetos SqlCommand y SqlParameter , y se establecen sus propiedades. SqlDataReader ejecuta SqlCommand
y devuelve el conjunto de resultados del procedimiento almacenado, mostrándolos en la ventana de consola.
Nota
En lugar de crear objetos SqlCommand
y SqlParameter
y, a continuación, establecer propiedades en instrucciones independientes, puede usar uno de los constructores sobrecargados para establecer varias propiedades en una única instrucción.
static void GetSalesByCategory(string connectionString,
string categoryName)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create the command and set its properties.
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = "SalesByCategory";
command.CommandType = CommandType.StoredProcedure;
// Add the input parameter and set its properties.
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@CategoryName";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = categoryName;
// Add the parameter to the Parameters collection.
command.Parameters.Add(parameter);
// Open the connection and execute the reader.
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}: {1:C}", reader[0], reader[1]);
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}
}
}