2011-01-07 14 views
35

hay una pregunta en relación con esto:¿Cuándo se deben usar "SqlDbType" y "size" al agregar los parámetros de SqlCommand?

What's the best method to pass parameters to SQLCommand?

pero estoy con ganas de saber cuáles son las diferencias y si hay algún problema con los diferentes maneras.

lo general el uso de una estructura algo como esto:

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 bien, hay varias formas de agregar los parámetros cmd y me pregunto cuál es el 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"); 

que tiene la longitud de la 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 me preocupa más 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. ¿Hay casos en que esto no funcione? Puedo imaginar 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 yo diría es es mucho menos probable que cambie la longitud, ¿vale la pena retener?

+3

Si bien no responde su pregunta, ¿sabe que no necesita abrir la conexión antes de llamar 'SqlDataAdapter.Fill()', y que hay beneficio en no hacerlo? –

+0

@Rowland buen punto. Lo sabía, aunque ha sido un descuido en mi código. Creo que tomé el bloque de código original de algún lugar donde estaba usando un SqlDataReader, no un adaptador (¿Necesitas abrir la conexión para ese derecho?). Eso es lo que obtienes por la programación traviesa de copiar/pegar :-). Corregido en mi código ahora. – PeteT

+0

pensé en mencionarlo, ya que es uno de esos "consejos oscuros que la gente podría no conocer" –

Respuesta

49

En mi experiencia, me aseguraría hago estas cosas:

  • asegurarse de que eres tú que define el tipo de datos para el parámetro. ADO.NET hace un trabajo decente en adivinar, pero en algunos casos, puede ser terriblemente fuera - por lo que se evitaría este método:

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

    Dejar ADO.NET adivinar el tipo del parámetro por el valor pasado es complicado, y si no funciona por alguna razón, ¡esos son errores realmente difíciles de rastrear y encontrar! Imagine lo que sucede cuando pasa un DBNull.Value - ¿qué tipo de datos debe elegir ADO.NET?

    ¡Sea explícito, diga qué tipo es lo que quiere!

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

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

    Si usted 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!

Así, en su caso, el único método que realmente funciona para mí es este de aquí:

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

porque a) define el tipo de datos a utilizar de forma explícita, y b) define la longitud de la cadena explícitamente.

+0

Si está utilizando un procedimiento almacenado, ¿no puede obtener el tipo de parámetro de los metadatos provistos por SqlCommandBuilder.DeriveParameters (cmd)? – devinbost

+0

¿Debería pasar la Longitud en la definición de parámetro subyacente? Y si es así, ¿ese tipo de violación no es SECO? – tbone

4

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í es una cita de MSDN:

comandos con parámetros también pueden mejorar el rendimiento de ejecución de la consulta, ya que ayudan a la base de datos del servidor coincide con precisión el comando entrante con un plan de consulta en caché adecuada.

Más para leer en Execution Plan Caching and Reuse.

+0

Todas las opciones de Pete están paramétricas, por lo que me sorprendería si agregar los parámetros de diferentes maneras afecta el rendimiento; ciertamente no se menciona explícitamente en el artículo al que se ha vinculado. –

+4

No estoy de acuerdo. Lo que el artículo describe es que al definir el parámetro lo más exacto posible es más probable que se use un plan de consulta en caché y luego con un mayor rendimiento. La subsección Parámetroización simple dice esto: en SQL Server, el uso de parámetros o marcadores de parámetros en las instrucciones de Transact-SQL aumenta la capacidad del motor relacional para hacer coincidir las nuevas declaraciones SQL con los planes de ejecución existentes previamente compilados. – StefanE

Cuestiones relacionadas