ASP.NET Pasando apóstrofos en el parámetro

So I have my SqlDataSource with a SelectQuery defined as follows:

 SELECT * FROM table 
 WHERE UserName IN (@EmployeesIn);

With @EmployeesIn coming from a session variable Session["EmployeesIn"]. During Page_Load I'm taking an ArrayList members and putting the results into a string and setting the session variable:

 string employeesIn = "";
 foreach (string s in members)
 {
      employeesIn = employeesIn + "'" + s + "',";
 }

 employeesIn = employeesIn.TrimEnd(',');
 Session["EmployeesIn"] = employeesIn;

Writing the output to the console I can see the value of the parameter @EmployeesIn

 @EmployeesIn = 'bob', 'joe'

However, I'm getting zero results back ... and after monitoring from the database level I see the parameter is coming in as:

'''bob'',''joe'''

Then again if I just pass in one employee, I get results back from the SQL as expected and the parameter is passed correctly as just 'bob'. I suppose this is some safety that .NET provides against SQL injection attacks, however what's the safe way around this?

preguntado el 08 de noviembre de 11 a las 16:11

You mentioned ArrayList -- are you using v.NET > 1.1, or were you referring to a generic List<T>? -

5 Respuestas

Debes absolutamente use parameters for this, instead of including the values within the SQL itself. You can just generate the names for the parameters, so if you had three entries you'd generate SQL of:

SELECT * FROM table WHERE UserName IN (@p0, @p1, @p2)

and then fill in those three parameters from the three values.

// Or create the command earlier, of course
List<SqlParameter> parameters = new List<SqlParameter>();

StringBuilder inClause = new StringBuilder("(");
for (int i = 0; i < members.Count; i++)
{
    string parameterName = "@p" + i;
    inClause.Append(parameterName);
    if (i != members.Count - 1)
    {
        inClause.Append(", ");
    }
    // Adjust data type as per schema
    SqlParameter parameter = new SqlParameter(parameterName, SqlDbType.NVarChar);
    parameter.Value = members[i];
    parameters.Add(parameter);
}
inClause.Append(")");

// Now use inClause in the SQL, and parameters in the command parameters

respondido 09 nov., 11:01

The count of my members variable will vary at runtime, would this handle dynamic parameter counts.. say if members.Count > 3? - xhermit

Table Valued Parameters are a better choice: msdn.microsoft.com/en-us/library/bb675163.aspx . The subject of passing lists into SQL Server is covered at length at sommarskog.se/arrays-in-sql.html. - Remus Rusanu

Excellent solution. Sorry I misunderstood the first part to the solution, hence my question. I was able to loop through parameters and add to e.Command.Parameters in the SQLDataSource Selecting event. Worked great. - xhermit

@RemusRusanu: That certainly makes sense if there are going to be a lot of parameters - but if you only have "easy" query access and you know that there will be a limited number of parameters (e.g. the UI limits it to 20) does this work reasonably? - Jon Skeet

Recomiendo este artículo: msdn.microsoft.com/en-us/magazine/ee236412.aspx. Your approach has two of the common pitfalls highlighted there: parameter type data type precedence problems that result from using Unicode @params (this is easily preventable, use the SqlParameter constructor that accepts a SqlDbType as parameter) and the second problem is the plan cache re-compilation and pollution issues (there are really up to 20 different queries at play). So I would say it work 'reasonably', but can easily degrade to 'bad' if one is not careful. - Remus Rusanu

Creo que tienes tres opciones:

  1. Comma separated values - you can pass single parameter value as CSVs and split them out in the stored procedure. I don't like this idea ... too many limitations.
  2. XML - you can pass an XML string into the stored procedure and open it as a table using OPENXML. This will give you a table that you can use to do joins, inserts, etc., onto other tables.
  3. Parámetros con valores de tabla

respondido 08 nov., 11:20

The better way would be to user your members array to build the query using a parameter list:

SELECT * FROM table 
WHERE UserName IN (@EmployeesIn1, @EmployeesIn2, @EmployeesIn3, ... n);

Then loop through your member list, adding the parameters as necessary.

respondido 08 nov., 11:20

The first thing I noticed was how you're making you're comma demilited list. Try this out:

string employeesIn = string.Join(",", members.Select(x => string.format("'{0}'", x)).ToArray());

As for the parameter, you need to rethink your approach. Have you looked at table value parameters?

respondido 08 nov., 11:20

SQL Parameters can only represent a single value, you can however pass in multiple parameters such as:

var emps = members.Select( (e,i) => "@EMPLOYEE" + i).ToArray();
string sqlQuery = "SELECT * FROM table WHERE ";
sqlQuery+=string.Format("UserName IN ({0})", string.Join(",", emps));

//add SQL parameters used in query
for (int i = 0; i < members.Count; ++i) 
{
    parameters.Parameters.Add(new SqlParameter("@EMPLOYEE" + i, members[i])); 
}

respondido 08 nov., 11:20

I just tried that without much success. For instance: employeesIn = employeesIn + "''" + s + "'',"; - xhermit

Good solution, this is the same concept as Jon's I believe. - xhermit

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.