2008-11-19 9 views
45

consultas parametrizadas en .Net siempre tener este aspecto en los ejemplos:consultas con parámetros con LIKE y en condiciones

SqlCommand comm = new SqlCommand(@" 
    SELECT * 
    FROM Products 
    WHERE Category_ID = @categoryid 
", 
    conn); 
comm.Parameters.Add("@categoryid", SqlDbType.Int); 
comm.Parameters["@categoryid"].Value = CategoryID; 

Pero estoy corriendo en una pared de ladrillo tratando de hacer lo siguiente:

SqlCommand comm = new SqlCommand(@" 
    SELECT * 
    FROM Products 
    WHERE Category_ID IN (@categoryids) 
     OR name LIKE '%@name%' 
", 
    conn); 
comm.Parameters.Add("@categoryids", SqlDbType.Int); 
comm.Parameters["@categoryids"].Value = CategoryIDs; 
comm.Parameters.Add("@name", SqlDbType.Int); 
comm.Parameters["@name"].Value = Name; 

Dónde

  • CategoryIDs es una lista separada por comas de los números "123 456 789" (sin comillas)
  • nombre es una cadena, posiblemente con comillas simples y otros personajes malos

¿Cuál es la sintaxis correcta para esto?

+0

En clasule "IN" debe especificar todos los valores de comandos SQL. Y aun así, agregue valor a la colección "Parámetros". Si pasa el valor de cadena en SQL a través del valor del parámetro, no debe temer la inyección sql. – TcKs

+0

Puede escribir su consulta como 'DONDE nombrar COMO CONCAT ('%',?, '%')' –

Respuesta

56

Digamos que tiene los identificadores de su categoría en una matriz de enteros y Name es una cadena. El truco consiste en crear el texto del comando para permitirle ingresar todos sus identificadores de categoría como parámetros individuales y construir la coincidencia difusa para el nombre. Para hacer lo anterior, usamos un bucle para construir una secuencia de nombres de parámetros @ p0 a través de @ pN-1, donde N es el número de identificadores de categoría en el conjunto. Luego, construimos un parámetro y lo agregamos al comando con la identificación de categoría asociada como el valor para cada parámetro con nombre. Luego usamos la concatenación en el nombre en la consulta misma para permitir la búsqueda difusa en el nombre.

string Name = "someone"; 
int[] categoryIDs = new int[] { 238, 1138, 1615, 1616, 1617, 
           1618, 1619, 1620, 1951, 1952, 
           1953, 1954, 1955, 1972, 2022 }; 

SqlCommand comm = conn.CreateCommand(); 

string[] parameters = new string[categoryIDs.Length]; 
for(int i=0;i<categoryIDs.Length;i++) 
{ 
    parameters[i] = "@p"+i; 
    comm.Parameters.AddWithValue(parameters[i], categoryIDs[i]); 
} 
comm.Parameters.AddWithValue("@name",$"%{Name}%"); 
comm.CommandText = "SELECT * FROM Products WHERE Category_ID IN ("; 
comm.CommandText += string.Join(",", parameters) + ")"; 
comm.CommandText += " OR name LIKE @name"; 

Esta es una consulta totalmente parametrizada que debe hacer feliz a su DBA. Sospecho que, dado que son enteros, no constituiría un gran riesgo de seguridad simplemente construir el texto de comando directamente con los valores, sin dejar de parametrizar el nombre. Si los ID de su categoría están en una matriz de cadenas, simplemente divida la matriz en comas, conviértalas a un entero y guárdelas en la matriz de enteros.

Nota: Di matriz y la uso en el ejemplo, pero debería funcionar para cualquier colección, aunque su iteración probablemente difiera.

idea original de http://www.tek-tips.com/viewthread.cfm?qid=1502614&page=9

+10

su DBA se volverá loco si codifica los parámetros en el SQL incluso si son enteros, porque eso significa que el DB no puede usar un caché de declaración y tiene que volver a analizar el enunciado todo el tiempo. –

+0

Su solución aún está abierta para la inyección sql. por ejemplo si el nombre contenía:% '; drop table Orders; - – ttomsen

+0

@ttomsen gracias, no sé cómo me lo perdí. arreglado ahora – tvanfosson

10

Necesita "%" en el valor del parámetro sql.

SqlCommand comm = new SqlCommand("SELECT * FROM Products WHERE Category_ID IN (@categoryid1, @categoryid2) OR name LIKE @name", conn); 
comm.Parameters.Add("@categoryid1", SqlDbType.Int); 
comm.Parameters["@categoryid1"].Value = CategoryID[0]; 
comm.Parameters.Add("@categoryid2", SqlDbType.Int); 
comm.Parameters["@categoryid2"].Value = CategoryID[1]; 
comm.Parameters.Add("@name", SqlDbType.Int); 
comm.Parameters["@name"].Value = "%" + Name + "%"; 
-2

no está seguro de si este es el camino correcto, pero es una forma en que he hecho en el Antes

lista templist = nueva lista

comm.Parameters.Add ("@ CategoryIDs" , SqlDbType.varchar); comm.Parameters ["@categories"]. Value = string.join (",", templist.toarray())

+1

No. No puede parametrizar una lista de valores. Bueno, puedes, pero comparará Category_ID con el único * string * value '1,2,3', en lugar de comparar con cada valor entero en la lista. Esto tendrá resultados no deseados. :-) –

6

Este enfoque no funcionará. Período.

La cláusula IN espera una lista de parámetros en sí, por lo que cuando se enlaza parámetro uno a él, usted tendrá la oportunidad de pasar una valor.

Construya su cadena de extracto de cuenta dinámicamente, con la cantidad exacta de marcadores de posición de cláusula IN individuales que desea pasar, y luego agregue parámetros y vincule valores en un bucle.

+0

Otro truco es crear una gran cantidad de parámetros en SQL y enlazar valores repetidamente. Esto es poco elegante pero funciona porque IN (1,2,3) e IN (1,2,3, 1,2,3, 1,2) son predicados equivalentes. –

+0

Sí, no es lindo pero efectivo. El servidor resolverá los duplicados. – Tomalak

Cuestiones relacionadas