SqlParameter和IN语句

5
我需要以下查询:
createList(string commaSeparatedElements) {
    ...
    SqlCommand query = new SqlCommand("SELECT * FROM table WHERE id IN ("+commaSeparatedElements+")");
    ...
}

我希望使用参数化查询方式编写代码,这样可以检查字符串中的每个元素以防止 SQL 注入攻击。

伪代码:

createList(string commaSeparatedElements) {
    ...
    SqlParameterList elements = new SqlParameterList("@elements", SqlDbType.Int);
    SqlParameterList.Values = commaSeparatedElements.split(new Char[1] {','});
    SqlCommand query = new SqlCommand("SELECT * FROM table WHERE id IN (@elements)");
    query.Parameters.Add(elements);
    ...
}

在C#中是否存在类似的东西,还是我必须自己编写?

编辑:感谢所有答案。由于我尽量不使用我不理解的代码(在过去几天中有太多不好的经验),因此 Dapper 和表值参数,即使它们可能非常适合我的需求,也是禁止的。我只是做了一个循环。

string[] elements = commaSeparatedElements.split(new Char[1] {','});
StringList idParamList = new StringList();
for(int i=0;i<elements.Count;i++) {
    query.Parameters.AddWithValue("@element"+i,Convert.ToInt32(elements[i]));
    idParamList.Add("@element" + i);
}
SqlCommand query = new SqlCommand("SELECT * FROM table WHERE id IN ("+String.Join(",",idParamList)+")");

请查看此链接:https://dev59.com/fG855IYBdhLWcg3wKw5Y - Microsoft DN
7个回答

8
"Dapper"对此有一些神秘的解决方法:"
var ids = new List<int> {1,2,3,4,5};
var rows = conn.Query<SomeType>("select * from table where id in @ids",
      new { ids }).ToList();

您会注意到在in的使用中没有括号; "dapper"会自动识别并执行参数扩展。此外,它会为您处理所有命令细节,包括将数据映射回SomeType实例中。
在上面的示例中,它将扩展为等效于(大约):
int ids0 = 1, ids1 = 2, ids2 = 3, ids3 = 4, ids4 = 5;
var rows = conn.Query<SomeType>(
    "select * from table where id in (@ids0,@ids1,@ids2,@ids3,@ids4)",
      new { ids0, ids1, ids2, ids3, ids4 }).ToList();

3

SQL Server有一个非常适合存储同一“类型”多个值的数据结构 - 那就是表格。

值得庆幸的是,在最近几年中,他们引入了表值参数(Table-Valued Parameters),因此您可以在客户端代码中构建一个表格,并以自然的方式将其传递到SQL Server中,例如:

// Assumes connection is an open SqlConnection.
using (connection)
{
// Create a DataTable with the modified rows.
DataTable addedCategories = CategoriesDataTable.GetChanges(
    DataRowState.Added);

// Define the INSERT-SELECT statement.
string sqlInsert = 
    "INSERT INTO dbo.Categories (CategoryID, CategoryName)"
    + " SELECT nc.CategoryID, nc.CategoryName"
    + " FROM @tvpNewCategories AS nc;"

// Configure the command and parameter.
SqlCommand insertCommand = new SqlCommand(
    sqlInsert, connection);
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue(
    "@tvpNewCategories", addedCategories);
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.CategoryTableType";

// Execute the command.
insertCommand.ExecuteNonQuery();
}

这是最好的方式,但需注意:由于参数嗅探,TVPs可能会与存储过程出现问题。 - ta.speot.is

2
如果您声明

List<int> Ids = new List<int>();

并在那里添加您想要的ID。 将其转换为逗号分隔列表很容易,如下所示

string listOfIds = string.Join(",", Ids.Select(Id => Id.ToString()).ToArray());

然后将此字符串作为参数传递给您的参数化查询。


2
无法工作,因为我没有询问SELECT * FROM table WHERE id IN ("1,2,3"),而是询问SELECT * FROM table WHERE id IN (1,2,3) - Alexander

1
我使用类似这样的辅助方法。
/// <summary>
/// Adds a sequence of parameters to an existing parameter collection
/// </summary>
/// <typeparam name="T">Type of parameter values</typeparam>
/// <param name="parameters">Existing parameter collection</param>
/// <param name="pattern">Name pattern of parameters. Must be a valid <see langword="int"/> format string</param>
/// <param name="parameterType">Database type of parameters</param>
/// <param name="length">Length of parameter. 0 for numeric parameters</param>
/// <param name="values">Sequence of values</param>
/// <returns>Comma separated string of parameter names</returns>
public static string AddParameters<T>(SqlParameterCollection parameters,
                                      string pattern,
                                      SqlDbType parameterType,
                                      int length,
                                      IEnumerable<T> values) {
    if (parameters == null)
        throw new ArgumentNullException("parameters");
    if (pattern == null)
        throw new ArgumentNullException("pattern");
    if (values == null)
        throw new ArgumentNullException("values");
    if (!pattern.StartsWith("@", StringComparison.CurrentCultureIgnoreCase))
        throw new ArgumentException("Pattern must start with '@'");

    var parameterNames = new List<string>();
    foreach (var item in values) {
        var parameterName = parameterNames.Count.ToString(pattern, CultureInfo.InvariantCulture);
        parameterNames.Add(parameterName);
        parameters.Add(parameterName, parameterType, length).Value = item;
    }

    return string.Join(",", parameterNames.ToArray());
}

It is used like this

string sql = "SELECT col1 " +
             "FROM Table " +
             "WHERE col2 IN ({@Values}) ";
var paramNames = SqlHelper.AddParameters(command.Parameters,
                                         "@Value0",
                                         SqlDbType.Int,
                                         0,
                                         listOfInts);
command.CommandText = sql.Replace("{@Values}", paramNames);
...

(结果是一个查询,类似于SELECT ... IN (@Value0, @Value1, @Value2)

1

0

这是我在一个项目中所做的:

        StringBuilder sb = new StringBuilder("Id IN(");
        List<SqlParameter> parameters = new List<SqlParameter>();
        int i = 1;

        foreach (int item in items)
        {
            string currentItem = "@Item" + i++.ToString();
            sb.Append(currentItem + ",");
            parameters.Add(new SqlParameter(currentItem , item));
        }
        sb.Remove(sb.Length-1, 1);

        sb.Append(")");

希望这能有所帮助


-1

或者你可以为参数设置一个if条件。例如:

if(commaSeparatedElements.Contains("'"))
   return;
else
   //Pass parameter & Execute query 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接