Como configurar parâmetros e tipos de dados de parâmetro

Objetos de comando usam parâmetros para passar valores para instruções SQL ou procedimentos armazenados, fornecendo verificação de tipo e validação. Diferentemente do texto de comando, o parâmetro de entrada é tratado como um valor literal, não como código executável. Isso ajuda a proteger contra ataques de "Injeção de SQL", em que um invasor insere um comando que compromete a segurança no servidor em uma instrução SQL.

Os comandos parametrizados também podem melhorar o desempenho de execução da consulta, porque ajudam o servidor de banco de dados a corresponder exatamente ao comando de entrada com um plano de consulta em cache apropriado. Para obter mais informações, confira Reutilização e armazenamento em cache do plano de execução e Parâmetros e reutilização de plano de execução. Além dos benefícios de segurança e desempenho, os comandos parametrizados fornecem um método conveniente para organizar os valores passados para uma fonte de dados.

Um objeto DbParameter pode ser criado usando o construtor ou adicionando-o ao DbParameterCollection chamando o método Add da coleção DbParameterCollection. O método Add utilizará como entrada argumentos de construtor ou um objeto de parâmetro existente, dependendo do provedor de dados.

Fornecer a propriedade ParameterDirection

Ao adicionar parâmetros, você deverá fornecer uma propriedade ParameterDirection para parâmetros diferentes dos parâmetros de entrada. A tabela a seguir mostra os valores ParameterDirection que você pode usar com a enumeração ParameterDirection.

Nome do membro Descrição
Input O parâmetro é um parâmetro de entrada. Este é o padrão.
InputOutput O parâmetro pode executar entrada e saída.
Output O parâmetro é um parâmetro de saída.
ReturnValue O parâmetro representa um valor de retorno de uma operação como um procedimento armazenado, uma função interna ou uma função definida pelo usuário.

Trabalhar com espaços reservados de parâmetro

A sintaxe para espaços reservados de parâmetro depende da fonte de dados. Os provedores de dados .NET Framework processam a nomeação e a especificação de parâmetros e de espaços reservados de parâmetros de maneira diferente. Essa sintaxe é personalizada para uma fonte de dados específica, conforme descrito na tabela a seguir.

Provedor de dados Sintaxe de nomeação de parâmetro
System.Data.SqlClient Usa parâmetros nomeados no formato @parametername.
System.Data.OleDb Usa os marcadores de parâmetros posicionais indicados por um ponto de interrogação (?).
System.Data.Odbc Usa os marcadores de parâmetros posicionais indicados por um ponto de interrogação (?).
System.Data.OracleClient Usa parâmetros nomeados no formato :parmname (ou parmname).

Especificar tipos de dados de parâmetros

O tipo de dados de um parâmetro é específico do provedor de dados .NET Framework. A especificação do tipo converte o valor do Parameter no tipo de provedor de dados .NET Framework antes de transmitir o valor para a fonte de dados. Você também pode especificar o tipo de um Parameter genericamente definindo a propriedade DbType de um objeto Parameter para um DbType específico.

O tipo do provedor de dados .NET Framework de um objeto Parameter é inferido do tipo .NET Framework do Value do objeto Parameter ou do DbType do objeto Parameter. A tabela a seguir mostra o tipo inferido de Parameter baseado no objeto passado como o valor do Parameter ou DbType especificado.

Tipo de .NET Framework DbType SqlDbType OleDbType OdbcType OracleType
Boolean Booliano bit Booliano bit Byte
Byte Byte TinyInt UnsignedTinyInt TinyInt Byte
byte[] Binário VarBinary. Essa conversão implícita falhará se a matriz de bytes for maior que o tamanho máximo de um VarBinary, que é 8.000 bytes. Para matrizes de bytes acima de 8.000 bytes, defina explicitamente o SqlDbType. VarBinary Binário Raw
Char Inferir um SqlDbType do char não tem suporte. Char Char Byte
DateTime Datetime DateTime DBTimeStamp Datetime DateTime
DateTimeOffset DateTimeOffset DateTimeOffset no SQL Server 2008. Inferir um SqlDbType de DateTimeOffset não tem suporte em versões do SQL Server anteriores ao SQL Server 2008. Datetime
Decimal Decimal Decimal Decimal Numérico Número
Double Double Float Double Double Double
Single Single Real Single Real Float
Guid Guid UniqueIdentifier Guid UniqueIdentifier Raw
Int16 Int16 SmallInt SmallInt SmallInt Int16
Int32 Int32 int int int Int32
Int64 Int64 BigInt BigInt BigInt Número
Object Objeto Variante Variante Inferir um OdbcType de objeto não tem suporte. Blob
String String NVarChar. Essa conversão implícita falhará se a cadeia de caracteres for maior do que o tamanho máximo de um NVarChar, que é 4000 caracteres. Para cadeias de caracteres maiores que 4000 caracteres, defina explicitamente o SqlDbType. VarWChar NVarChar NVarChar
TimeSpan Hora Hora no SQL Server 2008. Inferir um SqlDbType de TimeSpan não tem suporte em versões do SQL Server anteriores ao SQL Server 2008. DBTime Hora Datetime
UInt16 UInt16 Inferir um SqlDbType do UInt16 não tem suporte. UnsignedSmallInt int UInt16
UInt32 UInt32 Inferir um SqlDbType do UInt32 não tem suporte. UnsignedInt BigInt UInt32
UInt64 UInt64 Inferir um SqlDbType do UInt64 não tem suporte. UnsignedBigInt Numérica Número
AnsiString VarChar VarChar VarChar VarChar
AnsiStringFixedLength Char Char Char Char
Moeda Money Moeda Inferir um OdbcType de Currency não tem suporte. Número
Data Data no SQL Server 2008. Inferir um SqlDbType de Date não tem suporte em versões do SQL Server anteriores ao SQL Server 2008. DBDate Data Datetime
SByte Inferir um SqlDbType do SByte não tem suporte. TinyInt Inferir um OdbcType do SByte não tem suporte. SByte
StringFixedLength NChar WChar NChar NChar
Hora Hora no SQL Server 2008. Inferir um SqlDbType de Time não tem suporte em versões do SQL Server anteriores ao SQL Server 2008. DBTime Hora Datetime
VarNumeric Inferir um SqlDbType do VarNumeric não tem suporte. VarNumeric Inferir um OdbcType do VarNumeric não tem suporte. Número
tipo definido pelo usuário (um objeto com SqlUserDefinedAggregateAttribute Objeto ou cadeia de caracteres, dependendo do provedor (SqlClient sempre retorna um objeto, ODBC sempre retorna uma cadeia de caracteres e o provedor de dados gerenciados OleDb pode ver se SqlDbType.Udt se SqlUserDefinedTypeAttribute está presente, caso contrário Variant OleDbType.VarWChar (se o valor for nulo); caso contrário OleDbType.Variant. OdbcType.NVarChar sem suporte

Observação

Conversões de decimal para outros tipos são conversões de limitação que arredondam o valor decimal para o valor inteiro mais próximo de zero. Se o resultado da conversão não for representável no tipo de destino, um OverflowException será gerado.

Observação

Quando você envia um valor de parâmetro nulo para o servidor, deve especificar DBNull, não null (Nothing no Visual Basic). O valor nulo no sistema é um objeto vazio que não tem nenhum valor. DBNull é usado para representar valores nulos. Para obter mais informações sobre valores nulos de banco de dados, confira Como lidar com valores nulos.

Derivar informações de parâmetro

Os parâmetros também podem ser derivados de um procedimento armazenado usando a classe DbCommandBuilder. As classes SqlCommandBuilder e OleDbCommandBuilder fornecem um método estático, DeriveParameters, que preenche automaticamente a coleção de parâmetros de um objeto de comando que usa informações de parâmetro de um procedimento armazenado. Observe que DeriveParameters substitui qualquer informação de parâmetro existente para o comando.

Observação

Derivar informações de parâmetro provoca uma penalidade de desempenho porque exige ida e volta adicional à fonte de dados para recuperar as informações. Se as informações de parâmetro forem conhecidas em tempo de design, você poderá melhorar o desempenho do seu aplicativo definindo os parâmetros explicitamente.

Para obter mais informações, confira Gerar comandos com CommandBuilders.

Usar parâmetros com um SqlCommand e um procedimento armazenado

Os procedimentos armazenados oferecem várias vantagens em aplicativos orientados a dados. Ao usar procedimentos armazenados, as operações de banco de dados podem ser encapsuladas em um único comando, otimizadas para melhor desempenho e aprimoradas com segurança adicional. Embora um procedimento armazenado possa ser chamado passando o nome do procedimento armazenado seguido por argumentos de parâmetros como uma instrução SQL, usar a coleção de Parameters do objeto DbCommand do ADO.NET permite definir mais explicitamente os parâmetros de procedimento armazenados e acessar parâmetros de saída e valores de retorno.

Observação

As instruções parametrizadas são executadas no servidor usando sp_executesql, que permite a reutilização do plano de consulta. Os cursores locais ou variáveis no lote sp_executesql não são visíveis para os lotes que chamam sp_executesql. As alterações no contexto de banco de dados duram somente até o final da instrução sp_executesql. Para saber mais, confira sp_executesql (Transact-SQL).

Ao usar parâmetros com um SqlCommand para executar um procedimento armazenado do SQL Server, os nomes dos parâmetros adicionados à coleção de Parameters devem coincidir com os nomes dos marcadores de parâmetros no procedimento armazenado. O Provedor de Dados .NET Framework para o SQL Server não dá suporte ao espaço reservado de ponto de interrogação (?) para transmitir parâmetros para uma instrução SQL ou um procedimento armazenado. Ele trata parâmetros no procedimento armazenado como parâmetros nomeados e procura marcadores de parâmetro compatíveis. Por exemplo, o procedimento armazenado CustOrderHist é definido usando um parâmetro chamado @CustomerID. Quando o código executar o procedimento armazenado, também deverá usar um parâmetro chamado @CustomerID.

CREATE PROCEDURE dbo.CustOrderHist @CustomerID varchar(5)

Exemplo

Este exemplo demonstra como chamar um procedimento armazenado do SQL Server no banco de dados de exemplo Northwind. O nome do procedimento armazenado é dbo.SalesByCategory e tem um parâmetro de entrada chamado @CategoryName com um tipo de dados de nvarchar(15). O código cria um novo SqlConnection dentro de um bloco using para que a conexão seja descartada quando o procedimento terminar. Os objetos SqlCommand e SqlParameter são criados e suas propriedades são definidas. Um SqlDataReader executa o SqlCommand e retorna o conjunto de resultados do procedimento armazenado, exibindo a saída na janela do console.

Observação

Em vez de criar objetos SqlCommand e SqlParameter e depois definir as propriedades em instruções separadas, você poderá eleger usar um dos construtores sobrecarregados para definir várias propriedades em uma única instrução.

static void GetSalesByCategory(string connectionString,
    string categoryName)
{
    using (SqlConnection connection = new(connectionString))
    {
        // Create the command and set its properties.
        SqlCommand command = new()
        {
            Connection = connection,
            CommandText = "SalesByCategory",
            CommandType = CommandType.StoredProcedure
        };

        // Add the input parameter and set its properties.
        SqlParameter parameter = new()
        {
            ParameterName = "@CategoryName",
            SqlDbType = SqlDbType.NVarChar,
            Direction = ParameterDirection.Input,
            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();
        }
    }
}
Shared Sub GetSalesByCategory(ByVal connectionString As String, _
    ByVal categoryName As String)

    Using connection As New SqlConnection(connectionString)

        ' Create the command and set its properties.
        Dim command As SqlCommand = New SqlCommand()
        command.Connection = connection
        command.CommandText = "SalesByCategory"
        command.CommandType = CommandType.StoredProcedure

        ' Add the input parameter and set its properties.
        Dim parameter As 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 reader As SqlDataReader = command.ExecuteReader()

            If reader.HasRows Then
                Do While reader.Read()
                    Console.WriteLine("{0}: {1:C}", _
                      reader(0), reader(1))
                Loop
            Else
                Console.WriteLine("No rows returned.")
            End If
        End Using
    End Using
End Sub

Como usar parâmetros com um OleDbCommand ou um OdbcCommand

Ao usar parâmetros com um OleDbCommand ou OdbcCommand, a ordem dos parâmetros adicionados à coleção de Parameters deve coincidir com a ordem dos parâmetros definidos no procedimento armazenado. O Provedor de Dados .NET Framework para OLE DB e o Provedor de Dados .NET Framework para ODBC tratam os parâmetros em um procedimento armazenado como espaços reservados e aplicam os valores de parâmetro na ordem. Além disso, os parâmetros do valor de retorno devem ser os primeiros parâmetros adicionados à coleção de Parameters.

O Provedor de Dados .NET Framework para OLE DB e o Provedor de Dados .NET Framework para ODBC não dão suporte aos parâmetros nomeados para transmissão de parâmetros para uma instrução SQL ou um procedimento armazenado. Nesse caso, você deverá usar o espaço reservado de ponto de interrogação (?), como no exemplo a seguir.

SELECT * FROM Customers WHERE CustomerID = ?

Como resultado, a ordem na qual os objetos Parameter são adicionados à coleção de Parameters deve corresponder diretamente à posição do espaço reservado do ? para o parâmetro.

Exemplo de OleDb

Dim command As OleDbCommand = New OleDbCommand( _
  "SampleProc", connection)
command.CommandType = CommandType.StoredProcedure

Dim parameter As OleDbParameter = command.Parameters.Add( _
  "RETURN_VALUE", OleDbType.Integer)
parameter.Direction = ParameterDirection.ReturnValue

parameter = command.Parameters.Add( _
  "@InputParm", OleDbType.VarChar, 12)
parameter.Value = "Sample Value"

parameter = command.Parameters.Add( _
  "@OutputParm", OleDbType.VarChar, 28)
parameter.Direction = ParameterDirection.Output
OleDbCommand command = new OleDbCommand("SampleProc", connection);
command.CommandType = CommandType.StoredProcedure;

OleDbParameter parameter = command.Parameters.Add(
  "RETURN_VALUE", OleDbType.Integer);
parameter.Direction = ParameterDirection.ReturnValue;

parameter = command.Parameters.Add(
  "@InputParm", OleDbType.VarChar, 12);
parameter.Value = "Sample Value";

parameter = command.Parameters.Add(
  "@OutputParm", OleDbType.VarChar, 28);
parameter.Direction = ParameterDirection.Output;

Exemplo de ODBC

Dim command As OdbcCommand = New OdbcCommand( _
  "{ ? = CALL SampleProc(?, ?) }", connection)
command.CommandType = CommandType.StoredProcedure

Dim parameter As OdbcParameter = command.Parameters.Add("RETURN_VALUE", OdbcType.Int)
parameter.Direction = ParameterDirection.ReturnValue

parameter = command.Parameters.Add( _
  "@InputParm", OdbcType.VarChar, 12)
parameter.Value = "Sample Value"

parameter = command.Parameters.Add( _
  "@OutputParm", OdbcType.VarChar, 28)
parameter.Direction = ParameterDirection.Output
OdbcCommand command = new OdbcCommand( _
  "{ ? = CALL SampleProc(?, ?) }", connection);
command.CommandType = CommandType.StoredProcedure;

OdbcParameter parameter = command.Parameters.Add( _
  "RETURN_VALUE", OdbcType.Int);
parameter.Direction = ParameterDirection.ReturnValue;

parameter = command.Parameters.Add( _
  "@InputParm", OdbcType.VarChar, 12);
parameter.Value = "Sample Value";

parameter = command.Parameters.Add( _
  "@OutputParm", OdbcType.VarChar, 28);
parameter.Direction = ParameterDirection.Output;

Confira também