¿Cuál es el mejor método para pasar parámetros a SQLCommand?

¿Cuál es el mejor método para pasar parámetros a SQLCommand? Tu puedes hacer:

cmd.Parameters.Add("@Name", SqlDbType.VarChar, 20).Value = "Bob"; 

o

 cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = "Bob"; 

o

 cmd.Parameters.Add("@Name").Value = "Bob"; 

Parece que el primero podría ser de alguna manera “mejor”, ya sea en cuanto a rendimiento o error de comprobación. Pero me gustaría saber más definitivamente.

También puede usar AddWithValue() , pero tenga en cuenta la posibilidad de una conversión de tipo implícita incorrecta.

 cmd.Parameters.AddWithValue("@Name", "Bob"); 

¿Qué está pasando allí?

Citas las listas de parámetros para varias sobrecargas de Add . Estos son métodos de conveniencia que corresponden directamente a sobrecargas de constructor para la clase SqlParameter . Básicamente construyen el objeto de parámetro usando cualquier constructor que tenga la misma firma que el método de conveniencia que SqlParameterCollection.Add(SqlParameter) , y luego llaman a SqlParameterCollection.Add(SqlParameter) esta manera:

 SqlParameter foo = new SqlParameter(parameterName, dbType, size); this.Add(foo); 

AddWithValue es similar pero lleva la comodidad incluso más allá, y también establece el valor. Sin embargo, en realidad se introdujo para resolver un defecto del marco. Para citar MSDN,

La sobrecarga de Add que toma una cadena y un objeto quedó en desuso debido a la posible ambigüedad con la sobrecarga SqlParameterCollection.Add que toma un valor de enumeración String y SqlDbType donde pasar un entero con la cadena podría interpretarse como el valor del parámetro o el valor SqlDbType correspondiente. Use AddWithValue cada vez que quiera agregar un parámetro especificando su nombre y valor.

Las sobrecargas de constructor para la clase SqlParameter son meras conveniencias para establecer propiedades de instancia. Acortan el código, con un impacto marginal en el rendimiento: el constructor puede eludir los métodos de establecimiento y operar directamente en miembros privados. Si hay una diferencia, no será mucho.

¿Que debería hacer?

Tenga en cuenta lo siguiente (desde MSDN)

Para parámetros bidireccionales y de salida, y valores devueltos, debe establecer el valor de Size . Esto no es necesario para los parámetros de entrada, y si no se establece explícitamente, el valor se deduce del tamaño real del parámetro especificado cuando se ejecuta una instrucción parametrizada.

El tipo predeterminado es entrada. Sin embargo, si permite inferir el tamaño de esta manera y recicla el objeto parámetro en un bucle (dijo que estaba preocupado por el rendimiento), entonces el tamaño se establecerá por el primer valor y cualquier valor posterior que sea más largo será cortado. Obviamente, esto es significativo solo para valores de longitud variable como cadenas.

Si está pasando repetidamente el mismo parámetro lógico en un bucle, le recomiendo que cree un objeto SqlParameter fuera del bucle y que lo dimensione adecuadamente. Sobredimensionar un varchar es inofensivo, por lo que si es un PITA para obtener el máximo exacto, simplemente configúrelo más grande de lo que espera que sea la columna. Debido a que está reciclando el objeto en lugar de crear uno nuevo para cada iteración, es probable que disminuya el consumo de memoria durante la duración del ciclo, incluso si se emociona un poco con el sobredimensionamiento.

A decir verdad, a menos que proceses miles de llamadas, nada de esto hará mucha diferencia. AddWithValue crea un nuevo objeto, eludiendo el problema de tamaño. Es corto, dulce y fácil de entender. Si recorres miles, utiliza mi enfoque. Si no lo hace, use AddWithValue para mantener su código simple y fácil de mantener.


2008 fue hace mucho tiempo

En los años transcurridos desde que escribí esto, el mundo ha cambiado. Hay nuevos tipos de citas, y también hay un problema que no se me pasó por la cabeza hasta que un problema reciente con las fechas me hizo pensar en las implicaciones de la ampliación.

La ampliación y el estrechamiento, para quienes no estén familiarizados con los términos, son cualidades de las conversiones de tipos de datos. Si asigna un int a un doble, no hay pérdida de precisión porque el doble es “más ancho”. Siempre es seguro hacerlo, por lo que la conversión es automática. Esta es la razón por la que puede asignar un int a un doble, pero yendo al otro lado, tiene que hacer un reparto explícito: double to int es una conversión de estrechamiento con una posible pérdida de precisión.

Esto puede aplicarse a cadenas de caracteres: NVARCHAR es más ancho que VARCHAR, por lo que puede asignar un VARCHAR a un NVARCHAR, pero para el otro sentido requiere un lanzamiento. La comparación funciona porque VARCHAR se amplía implícitamente a NVARCHAR, ¡ pero esto interferirá con el uso de índices!

Las cadenas de C # son Unicode, por lo que AddWithValue generará un parámetro NVARCHAR. En el otro extremo, los valores de columna VARCHAR se amplían a NVARCHAR para comparación. Esto no detiene la ejecución de consultas pero evita que se usen índices. Esto es malo.

¿Qué puedes hacer al respecto? Tienes dos soluciones posibles.

  • Escriba explícitamente el parámetro. Esto significa que no hay más AddWithValue
  • Cambie todos los tipos de columna de cadena a NVARCHAR.

El abandono de VARCHAR es probablemente la mejor idea. Es un cambio simple con consecuencias predecibles y mejora su historia de localización. Sin embargo, es posible que no tengas esto como una opción.

En estos días no hago mucho ADO.NET directo. Linq2Sql es ahora mi arma de elección, y el hecho de escribir esta actualización me ha dejado preguntándome cómo maneja este problema. Tengo un deseo repentino y ardiente de purgar mis bases de datos de VARCHAR.

Yo diría que el # 1 seguro. Pero, sin embargo, Microsoft lo hace en el bloque de aplicaciones de acceso a datos en la biblioteca de la empresa es el mejor, especialmente para el servidor SQL:

http://msdn.microsoft.com/en-us/library/dd203144.aspx

Solía ​​usar tu opción 1:

cmd.Parameters.Add (“@ Name”, SqlDbType.VarChar, 20) .Value = “Bob”;

que funcionó bien, pero luego comencé a usar .AddWithValue y es tan simple como se pone. No me ha causado ningún problema después de muchos miles de usos. Eso sí, casi siempre paso las variables privadas de mis clases, por lo que no tengo que preocuparme tanto por la conversión de tipo implícita.

Depende de su aplicación. De hecho, me gusta 2, porque no tengo que cambiar mi DAO si cambio la longitud de un parámetro de proceso almacenado. Aunque soy solo yo. No sé si hay penalizaciones por desempeño o algo.