【问题标题】:Passing List<int> as Query Parameter to SQL Server将 List<int> 作为查询参数传递给 SQL Server
【发布时间】:2016-02-25 05:46:10
【问题描述】:

我必须使用 C# 将列表传递给 SQL Server 查询。我的代码在这里:

using (SqlDataReader _myReader_2 = _myCommand_3.ExecuteReader())
{
    _Node_Neighbor.Clear();
        while (_myReader_2.Read())
        {
            _Node_Neighbor.Add(Convert.ToInt32(_myReader_2["Target_Node"]));
        }

    _myReader_2.Close();

  //Here I have to pass this _Node_Neighbor i.e. of type List<int> to another  
  //SQL Server query as:

    try
        {
            SqlCommand _myCommand_4 = _con.CreateCommand();

            _myCommand_4.CommandText = @"SELECT COUNT(*) FROM GraphEdges
                                         WHERE Source_Node IN @Source_Node 
                                         AND Target_Node IN @Target_Node";

            _myCommand_4.Parameters.AddWithValue("@Source_Node", _Node_Neighbor);
            _myCommand_4.Parameters.AddWithValue("@Target_Node", _Node_Neighbor);

            _Mutual_Links = Convert.ToInt32(_myCommand_4.ExecuteScalar());
        }
        catch(Exception e)
        {
            Console.WriteLine(e.Message);
        }
}  

然而,要将列表作为参数传递,我认为可能还有其他方式,这就是我收到此错误的原因: No mapping exists from object type Systems.Collections.Generic.List

谢谢!

【问题讨论】:

  • 您需要使用 IN() 语法。但恐怕这不适用于参数。
  • 你试过_Node_Neighbor.ToArray() 吗?我很确定参数支持数组。
  • 为什么不直接格式化查询而不是使用参数? string.Format("...WHERE Source_Node IN ('{0}')...", string.Join("','", _Node_Neighbor))
  • 在查询中,您将@_Node_Neighbor 作为参数,但在添加值时,您将@Source_Node 作为参数名称传递
  • 您可以使用 TVP 而不是使用 IN 子句传递。检查这个问题stackoverflow.com/questions/20143012/… 和这个答案stackoverflow.com/a/20143173/311255

标签: c# sql-server list parameter-passing


【解决方案1】:

为了为IN 传递数组/列表,您必须为列表中的每个值创建一个参数。

try
    {
        SqlCommand _myCommand_4 = _con.CreateCommand();


        List<string> sqlParams = new List<string>();
        int i = 0;
        foreach(var value in _Node_Neighbor){
            var name = "@p"  + i++;
            _myCommand_4.Parameters.Add(name,value);
            sqlParams.Add(name);
        }

        string paramNames = string.Join(",", sqlParams);

        _myCommand_4.CommandText = "SELECT COUNT(*) FROM GraphEdges"
                       " WHERE Source_Node IN (" + paramNames + ") " 
                         " AND Target_Node IN (" + paramNames + ")";


        _Mutual_Links = Convert.ToInt32(_myCommand_4.ExecuteScalar());
    }
    catch(Exception e)
    {
        Console.WriteLine(e.Message);
    }

【讨论】:

  • 仅供参考,您应该在查询中使用 string.Format 而不是连接 paramNames 以避免 sql 注入。
  • @JonathanCarroll, i 是整数,不必要的字符串。格式是简单连接的负担。仅当您在 sql 字符串中附加非值类型时,才会发生 Sql 注入。在这个世界上,这不可能导致 SQL 注入。在其他答案中,值可能是非值类型,这可能会导致 SQL 注入,因为它们来自代码外部。
【解决方案2】:

sql server 中使用用户定义的表ADO.NET 代码中的数据表。

【讨论】:

  • 扩展该答案会很好。现在的样子,只不过是一条评论而已。
【解决方案3】:

如果数组不大,在c#中构建动态查询

using (SqlDataReader _myReader_2 = _myCommand_3.ExecuteReader())
        {
            _Node_Neighbor.Clear();
            while (_myReader_2.Read())
            {
                _Node_Neighbor.Add(Convert.ToInt32(_myReader_2["Target_Node"]));
            }

            _myReader_2.Close();

            //Here I have to pass this _Node_Neighbor i.e. of type List<int> to another  
            //SQL Server query as:

            try
            {
                var query = @"SELECT COUNT(*) FROM GraphEdges
                WHERE Source_Node IN

                (##Source_Node)

                AND Target_Node IN 
                (##Target_Node)";
                var sourceNode = "";
                foreach (var item in _Node_Neighbor)
                {
                    sourceNode += item + ",";
                }

                sourceNode = sourceNode.TrimEnd(',');

                var targetNode = "";
                foreach (var item in _Node_Neighbor)
                {
                    targetNode += item + ",";
                }

                targetNode = targetNode.TrimEnd(',');

                query = query.Replace("##Source_Node", sourceNode).Replace("##Target_Node", targetNode);

                SqlCommand _myCommand_4 = _con.CreateCommand();

                _myCommand_4.CommandText = @"SELECT COUNT(*) FROM GraphEdges
                                     WHERE Source_Node IN @Source_Node 
                                     AND Target_Node IN @Target_Node";


                _Mutual_Links = Convert.ToInt32(_myCommand_4.ExecuteScalar());
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-24
    • 2014-04-06
    • 2013-08-02
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多