¿Cuándo se deben usar “SqlDbType” y “size” al agregar los parámetros de SqlCommand?

Hay una pregunta relacionada con esto:

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

Pero quiero saber cuáles son las diferencias y si hay algún problema con las diferentes formas.

Usualmente uso una estructura como esta:

using (SqlConnection conn = new SqlConnection(connectionString)) using (SqlCommand cmd = new SqlCommand(SQL, conn)) { cmd.CommandType = CommandType.Text; cmd.CommandTimeout = Settings.Default.reportTimeout; cmd.Parameters.Add("type", SqlDbType.VarChar, 4).Value = type; cmd.Connection.Open(); using (SqlDataAdapter adapter = new SqlDataAdapter(cmd)) { adapter.Fill(ds); } //use data } 

Ahora hay varias formas de agregar los parámetros cmd y me pregunto cuál es la mejor:

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

Tener la longitud del campo en el paso de los varchar, supongo que no es preferible, ya que es un valor mágico que se puede cambiar más adelante en la base de datos. ¿Es esto correcto? ¿Provoca algún problema que pase un varchar de esta manera (rendimiento u otro)? Supongo que tiene como valor predeterminado varchar (max) o el equivalente de la base de datos. Estoy razonablemente feliz de que esto funcione.

La parte que más me preocupa es la pérdida de la enumeración SqlDbType si utilizo la tercera o cuarta opción que enumeré anteriormente. No estoy suministrando ningún tipo de enum. ¿Hay casos en que esto no funcione? Puedo imaginarme problemas con varchar siendo incorrectamente lanzado a char o viceversa o quizás problemas con decimal a dinero …

En términos de la base de datos, el tipo de campo que diría es mucho menos probable que cambie, por lo que vale la pena conservarlo.

En mi experiencia, me aseguraría de hacer estas cosas:

  • asegúrese de que sea usted quien defina el tipo de datos para el parámetro. ADO.NET hace un trabajo decente al adivinar, pero en algunos casos, puede estar terriblemente mal, así que evitaría este método:

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

    Permitir que ADO.NET adivine el tipo de parámetro por el valor pasado es engañoso, y si está desactivado por alguna razón, ¡esos son realmente errores difíciles de rastrear y encontrar! Imagine lo que sucede cuando pasa un DBNull.Value : ¿qué tipo de datos debe elegir ADO.NET?

    Solo sea explícito, diga de qué tipo es lo que quiere.

  • Si está utilizando parámetros de cadena, asegúrese de definir explícitamente la longitud , por lo que también evitaría este método:

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

    Si no proporciona una longitud, ADO.NET puede establecer de forma predeterminada un valor arbitrario, o la longitud de la cadena pasada como un valor, o algo más: nunca está seguro. Y si su longitud no coincide con lo que realmente espera el proceso almacenado, es posible que vea la conversión y otras sorpresas desagradables. ¡Así que si defines una cadena, define su longitud también!

Entonces, en tu caso, el único enfoque que realmente funciona para mí es este:

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

porque a) define el tipo de datos para usar explícitamente, yb) define la longitud de la cadena explícitamente.

Al agregar el tipo, es más probable que sus solicitudes mejoren el rendimiento mediante el uso de un plan de consulta en caché.

Aquí hay una cita de MSDN:

Los comandos parametrizados también pueden mejorar el rendimiento de la ejecución de consultas, ya que ayudan al servidor de la base de datos a hacer coincidir con precisión el comando entrante con un plan de consulta en caché adecuado.

Más para leer en el almacenamiento en caché y la reutilización del plan de ejecución .