post icon

Parameters.Add vs Parameters.AddWithValue

Pareciera trivial usar uno u otro método para enviar parámetros desde .Net a las bases de datos, pero no lo es. Uno utiliza un método implícito (Parameters.AddWithValue) de conversión de datos y otro explicito (Parameters.Add)

Utilizar el método implícito es más sencillo pero puede acarrear varios problemas y a muchas veces no son fáciles de detectar:

Cuellos de botellas

Cuando escribía el post sobre las diferencias entre NVARCHAR y VARCHA de SQL Server hacía mención sobre el rendimiento que pueden tener  los tipos de datos y el envío de parámetros sin tipificarlos. Si no especificamos el tipo de dato del parámetro al enviar SQL Server considerará que es un NVARCHAR, si se da que se necesitaba un VARCHAR se convertirá entre estos tipos lo cual es bastante lento y difícil de detectar en donde se encuentra el cuello de botella porque no genera errores, y no se puede ver en los planes de ejecución.

Por una cuestión de desconocimiento la mayoría de los programadores utilizan el tipo VARCHAR en su base de datos mezclados con el envío de parámetros implícitos de .Net y sin darse cuenta están poniéndole una soga al cuello a su aplicación.

También podría repercutir en el caso de los índices, si se superan los límites de 450 o 900 caracteres según el caso.

Datos erróneos

Éstos errores consisten en almacenar los datos con el formato incorrecto produciendo incoherencias que pueden ser muy graves, principalmente se da con las fechas y números exactos como monedas, decimales, dobles y otros. Por ejemplo cuando escribimos esto:

Parameters.AddWithValue("valor", "10/04/2013");

Donde intentamos almacenar el 10 de abril de 2013, pero al no especificar el formato podría almacenarse el 4 de octubre de 2013.

Seguridad

Es muy típico encontrar ataques de SQL Injection y existen cientos de aplicaciones que son vulnerables a éste tipo de ataques, siendo que las medidas para defenderse de él son bastante sencillas y normalmente con el uso correcto de los objetos ya se cubre la mayoría de los casos.

Especificar el tipo de dato correcto, la longitud y otros parámetros del parámetro (valga la redundancia) hace que nuestra aplicación sea más robusta. Si tenemos un parámetro NVARCHAR(30) sería imposible que puedan inyectar una query más larga que esa, o si se recibe un tipo de dato que no sea de cadena, tampoco se podrá inyectar código SQL.

Siempre recomiendo evitar el acceso directo a las tablas de la base de datos, por cuestiones de seguridad y rendimiento conviene utilizar procedimientos almacenados en vez de querys empotradas.

Las maneras de enviar parametros son las siguientes, y las enumero desde la peor práctica a la mejor:

Concatenación de SQL

La peor práctica y la más difundida probablemente es ésta, prácticamente no tiene ningún mecanismo de defensa a ataques de SQL Injection a parte de problemas de rendimiento y errores de datos que puede conllevar.

cmd.Connection = conexion;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM tabla WHERE fecha ='" + "05/06/2013+ "'";

Parametrización empotrada

De esta manera se mejora en cierto modo la seguridad, ya que no puede inyectarse en todos los casos querys SQL y se evita errores de datos

cmd.Connection = conexion;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM Tabla WHERE fecha = @fecha";
cmd.Parameters.Add("@fecha", SqlDbType.DateTime).Value = "05/06/2013";

Usando Parameters.AddWithValue

De ésta manera se aumenta significativamente la seguridad aunque tiene mucha perdida potencial de rendimiento y generación de datos erroreos.

cmd.Connection = conexion;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText("prcProcedimientoAlmacenado");
cmd.Parameters.AddWithValue("@ParametroFecha", "05/07/2013");

Usando Parameters.Add

La mejor manera de todas es escribir código como este, implica un poco más de código (ni siquiera es mucho) y de este modo tenemos productos optimizados, estables y seguros.

cmd.Connection = conexion;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText("prcProcedimientoAlmacenado");
cmd.Parameters.Add("@ParametroFecha", SqlDbType.DateTime).Value = "21/07/2013";

Comentarios desde Facebook:

  1. avatar
    christian ramirez PERU Internet Explorer Windows
    27 agosto 2014 at 16:16 #

    excelente mi estimado, post asi es lo que un programador necesita, sigue asi con las buenas practicas, gracias. saludos desde peru

  2. avatar
    Joaquín Bresan ARGENTINA Mozilla Firefox Windows
    2 marzo 2014 at 00:10 #

    Gran aporte amigo, muy interesante la info acerca de los buenos habitos al Programar. Muchas Gracias.

Responder