【问题标题】:C# MySQL adding multiple of the same parameter with a loopC# MySQL用循环添加多个相同的参数
【发布时间】:2017-02-21 04:50:41
【问题描述】:

更新:由于原始问题基本上已得到回答,因此我已将其标记为完成。


我有一个 C# 项目,我想在其中查询数据库。 SQL 查询将从表中选择,在 WHERE 子句中,我想从 C# 中指定的预定义值列表中过滤结果。

List<string> productNames = new List<string >() { "A", "B", "C" };

foreach (name in productNames)
{
    string query = @"
        SELECT *
        FROM products
        WHERE name IN (@name);";

    // Execute query
    MySqlCommand cmd = new MySqlCommand(query, dbConn);
    cmd.Parameters.AddWithValue("name", name);

    MySqlDataReader row = cmd.ExecuteReader();
    while (row.Read())
    {
        // Process result
        // ...
    }
}

但是我遇到了一个错误:

已经有一个打开的 DataReader 与此 Connection 关联 必须先关闭

那么就不能使用for 循环以这种方式将参数添加到 SELECT 语句吗?

【问题讨论】:

    标签: c# mysql


    【解决方案1】:

    您需要处理您的对象以免发生异常。但是,您不需要遍历值并为列表中的每个值运行查询。试试下面的代码。它为每个值创建一个参数,并将其添加到命令中以在“IN (...)”子句中使用。

    “使用”关键字也处理对象的处置。

    List<string> productsIds = new List<string>() { "23", "46", "76", "88" };
            string query = @"
                SELECT *
                FROM products
                WHERE id IN ({0});";
    
            // Execute query
            using (MySqlCommand cmd = new MySqlCommand(query, dbConn))
            {
                int index = 0;
                string sqlWhere = string.Empty;
                foreach (string id in productsIds)
                {
                    string parameterName = "@productId" + index++;
                    sqlWhere += string.IsNullOrWhiteSpace(sqlWhere) ? parameterName : ", " + parameterName;
                    cmd.Parameters.AddWithValue(parameterName, id);
                }
    
                query = string.Format(query, sqlWhere);
                cmd.CommandText = query;
                using (MySqlDataReader row = cmd.ExecuteReader())
                {
                    while (row.Read())
                    {
                        // Process result
                        // ...
                    }
                }
            }
    

    【讨论】:

      【解决方案2】:

      你做错了几件事。让我指出它们:

      • 在循环的第一次迭代中一切正常,当您进行第二次迭代时,与该命令关联的 First Reader 保持打开状态并导致当前错误。
      • 您正在使用Where IN(..),您可以将IN 中的值指定为逗号分隔,因此无需遍历参数。
      • 您可以使用String.Join 方法用逗号分隔符构造此值。

      现在看看下面的代码:

      List<int> productsIds = new List<int>() { 23, 46, 76, 88 };
      
      string idInParameter = String.Join(",", productsIds);
      
      // Create id as comma separated string
      string query = "SELECT * FROM products WHERE id IN (@productId);";
      
      MySqlCommand cmd = new MySqlCommand(query, dbConn);
      cmd.Parameters.AddWithValue("@productId", idInParameter);
      
      MySqlDataReader row = cmd.ExecuteReader();
      while (row.Read())
      {
          // Process result
          // ...
      }
      

      请注意,如果表中的 id 字段不是整数,那么您必须修改 idInParameter 的构造,如下所示:

      idInParameter = String.Join(",", productsIds.Select(x => "'" + x.ToString() + "'").ToArray());
      

      【讨论】:

      • 谢谢,这行得通。如果我想改用一个字符串列表怎么办,是一样的吗?我是否必须将参数括在引号中,例如:...WHERE id IN ('@myString'); ?
      • @user2181948:我已经更新了答案,请看一下
      • 使用字符串时找不到结果...但是当我将 idInParameter 的值直接复制并粘贴到 SQL 查询中,并注释掉 'cmd.Parameters.AddWithValue("productId", idInParameter )',然后找到结果...
      • 你错过了cmd.Parameters.AddWithValue("中的@吗?
      • 当我尝试使用@ 和不使用@ 时,发现零结果。这个符号的目的是什么?我之前只见过没有@符号的 cmd.Parameters.AddWithValue()
      【解决方案3】:

      传递逗号分隔的 productIds 字符串而不是循环。阅读有关 INhere 的更多信息。

       string productIdsCommaSeparated = string.Join(",", productsIds.Select(n => n.ToString()).ToArray())
         string query = @"
              SELECT *
              FROM products
              WHERE id IN (@productId);";
      
          // Execute query
          MySqlCommand cmd = new MySqlCommand(query, dbConn);
          cmd.Parameters.AddWithValue("productId", productIdsCommaSeparated );
      
          MySqlDataReader row = cmd.ExecuteReader();
          while (row.Read())
          {
              // Process result
              // ...
          }
      

      你得到的错误是因为你没有关闭 MySqlDataReader。在下一次迭代中调用 ExecuteReader 之前,您必须 close 它以消除错误,但在这种情况下这不是正确的方法。

      【讨论】:

        【解决方案4】:

        从我尝试和测试的结果来看,最好的解决方案(尤其是对于文本列类型)是创建单个参数的列表并将其作为范围添加到查询和参数中。

        例如:

        List<MySqlParameter> listParams = new List<MySqlParameter>();
        for (int i = 0; i < listOfValues.Length; i++) 
        {
            listParams.Add(new MySqlParameter(string.Format("@values{0}", i), 
                MySqlDbType.VarChar) { Value = listOfValues[i] });
        }
        
        string sqlCommand = string.Format("SELECT data FROM table WHERE column IN ({0})", 
            string.Join(",", listParams.Select(x => x.ParameterName)));
        
        ......
        
        using (MySqlCommand command = new MySqlCommand(sqlCommand, connection)
        {
            ............
            command.Parameters.AddRange(listParams.ToArray());
            ............
        }
        

        【讨论】:

          猜你喜欢
          • 2021-03-12
          • 2019-02-12
          • 1970-01-01
          • 1970-01-01
          • 2014-03-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多