Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Qual é o melhor método para passar parâmetros para SQLCommand?

O que está acontecendo lá dentro?


Você cita as listas de parâmetros para várias sobrecargas de Add . Esses são métodos de conveniência que correspondem diretamente a sobrecargas de construtor para o SqlParameter aula. Eles essencialmente constroem o objeto de parâmetro usando qualquer construtor que tenha a mesma assinatura que o método de conveniência que você chamou e, em seguida, chamam SqlParameterCollection.Add(SqlParameter) assim:
SqlParameter foo = new SqlParameter(parameterName, dbType, size);
this.Add(foo);

AddWithValue é semelhante, mas leva a conveniência ainda mais longe, também definindo o valor. No entanto, ele foi realmente introduzido para resolver uma falha da estrutura. Para citar o MSDN,

A sobrecarga de Add que recebe uma string e um objeto foi descontinuado devido a uma possível ambiguidade com oSqlParameterCollection.Add sobrecarga que recebe uma String e um SqlDbType valor de enumeração em que passar um inteiro com a string pode ser interpretado como sendo o valor do parâmetro ou oSqlDbType correspondente valor. Use AddWithValue sempre que desejar adicionar um parâmetro especificando seu nome e valor.

O construtor sobrecarrega para o SqlParameter class são meras conveniências para definir propriedades de instância. Eles encurtam o código, com impacto marginal no desempenho:o construtor pode ignorar métodos setter e operar diretamente em membros privados. Se houver diferença, não será muita.

O que devo fazer?


Observe o seguinte (do MSDN)

Para parâmetros bidirecionais e de saída e valores de retorno, você deve definir o valor de Size . Isso não é necessário para parâmetros de entrada e, se não for definido explicitamente, o valor é inferido do tamanho real do parâmetro especificado quando uma instrução parametrizada é executada.

O tipo padrão é entrada. No entanto, se você permitir que o tamanho seja inferido assim e reciclar o objeto de parâmetro em um loop (você disse que estava preocupado com o desempenho), o tamanho será definido pelo primeiro valor e quaisquer valores subsequentes que forem mais longos serão cortado. Obviamente, isso é significativo apenas para valores de comprimento variável, como strings.

Se você estiver passando o mesmo parâmetro lógico repetidamente em um loop, recomendo criar um objeto SqlParameter fora do loop e dimensioná-lo adequadamente. O superdimensionamento de um varchar é inofensivo, portanto, se for um PITA para obter o máximo exato, basta configurá-lo maior do que você espera que a coluna seja. Como você está reciclando o objeto em vez de criar um novo para cada iteração, o consumo de memória durante a duração do loop provavelmente cairá mesmo se você ficar um pouco animado com o superdimensionamento.

Verdade seja dita, a menos que você processe milhares de chamadas, nada disso fará muita diferença. AddWithValue cria um novo objeto, evitando o problema de dimensionamento. É curto e doce e fácil de entender. Se você percorrer milhares, use minha abordagem. Caso contrário, use AddWithValue para manter seu código simples e fácil de manter.

2008 foi há muito tempo


Nos anos desde que escrevi isso, o mundo mudou. Existem novos tipos de datas, e também há um problema que não me passou pela cabeça até que um problema recente com datas me fez pensar nas implicações da ampliação.

Ampliação e estreitamento, para aqueles que não estão familiarizados com os termos, são qualidades das conversões de tipo de dados. Se você atribuir um int a um double, não haverá perda de precisão porque double é "mais amplo". É sempre seguro fazer isso, então a conversão é automática. É por isso que você pode atribuir um int a um double, mas indo para o outro lado, você precisa fazer uma conversão explícita - double to int é uma conversão estreita com potencial perda de precisão.

Isso pode se aplicar a strings:NVARCHAR é mais largo que VARCHAR, então você pode atribuir um VARCHAR a um NVARCHAR, mas ir para o outro lado requer uma conversão. A comparação funciona porque o VARCHAR se amplia implicitamente para NVARCHAR, mas isso interferirá no uso de índices!

As cadeias de caracteres C# são Unicode, portanto, AddWithValue produzirá um parâmetro NVARCHAR. Na outra extremidade, os valores da coluna VARCHAR são ampliados para NVARCHAR para comparação. Isso não interrompe a execução da consulta, mas impede que os índices sejam usados. Isto é mau.

O que você pode fazer sobre isso? Você tem duas soluções possíveis.
  • Digite explicitamente o parâmetro. Isso significa que não há mais AddWithValue
  • Altere todos os tipos de coluna de string para NVARCHAR.

Abandonar o VARCHAR é provavelmente a melhor ideia. É uma mudança simples com consequências previsíveis e melhora sua história de localização. No entanto, você pode não ter isso como uma opção.

Hoje em dia eu não faço muito ADO.NET direto. O Linq2Sql agora é minha arma de escolha, e o ato de escrever esta atualização me deixou imaginando como ele lida com esse problema. Eu tenho um desejo repentino e ardente de verificar meu código de acesso a dados para pesquisa por meio de colunas VARCHAR.

2019 e o mundo mudou de novo


Linq2Sql não está disponível no dotnet Core, então estou usando o Dapper. O problema do [N]VARCHAR ainda existe, mas não está mais tão enterrado. Acredito que também se pode usar o ADO para que as coisas tenham um círculo completo a esse respeito.