【问题标题】:All rows are going as one row to stored procedure c#所有行都作为一行存储过程c#
【发布时间】:2016-05-14 16:45:48
【问题描述】:

我将数据表的数据发送到存储过程,该存储过程只是将数据插入表中,但出现错误

过程或函数 usp_InsertData 指定了太多参数。

当我使用分析器查看发生了什么时,我发现所有行都作为一行进入存储过程。

String strConnString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
SqlConnection con = new SqlConnection();

public static void InsertData(DataTable dt)
{
        String strConnString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
        SqlConnection con = new SqlConnection();
        con.ConnectionString = strConnString;

        SqlCommand cmd = new SqlCommand();
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.CommandText = ("usp_InsertData");
        cmd.Connection = con;

        con.Open();

        for (int i = 1; i < dt.Rows.Count; i++)
        {
            cmd.Parameters.AddWithValue("@FirstIssue", dt.Rows[i][0].ToString());
            cmd.Parameters.AddWithValue("@RTitle", dt.Rows[i][1].ToString());
            cmd.Parameters.AddWithValue("@RFirstName", dt.Rows[i][2].ToString());
            cmd.Parameters.AddWithValue("@RLastName", dt.Rows[i][3].ToString());
            cmd.Parameters.AddWithValue("@RAddress1", dt.Rows[i][4].ToString());
            cmd.Parameters.AddWithValue("@RAddress2", dt.Rows[i][5].ToString());
            cmd.Parameters.AddWithValue("@RAddress3", dt.Rows[i][6].ToString());
            cmd.Parameters.AddWithValue("@RCity", dt.Rows[i][7].ToString());
            cmd.Parameters.AddWithValue("@RZip", dt.Rows[i][8].ToString());
            cmd.Parameters.AddWithValue("@RCounty", dt.Rows[i][9].ToString());
            cmd.Parameters.AddWithValue("@RCountry", dt.Rows[i][10].ToString());
            cmd.Parameters.AddWithValue("@PTitle", dt.Rows[i][11].ToString());
            cmd.Parameters.AddWithValue("@PFirstName", dt.Rows[i][12].ToString());
            cmd.Parameters.AddWithValue("@PLastName", dt.Rows[i][13].ToString());
            cmd.Parameters.AddWithValue("@PAddress1", dt.Rows[i][14].ToString());
            cmd.Parameters.AddWithValue("@PAddress2", dt.Rows[i][15].ToString());
            cmd.Parameters.AddWithValue("@PAddress3", dt.Rows[i][16].ToString());
            cmd.Parameters.AddWithValue("@PCity", dt.Rows[i][17].ToString());
            cmd.Parameters.AddWithValue("@PZip", dt.Rows[i][18].ToString());
            cmd.Parameters.AddWithValue("@PCounty", dt.Rows[i][19].ToString());
            cmd.Parameters.AddWithValue("@PCountry", dt.Rows[i][20].ToString());
            cmd.Parameters.AddWithValue("@SubscriberAccountNumber", dt.Rows[i][21].ToString());
            cmd.Parameters.AddWithValue("@OnSaleDate", dt.Rows[i][22].ToString());
            cmd.Parameters.AddWithValue("@Subscriber", dt.Rows[i][23].ToString());

            try
            {
                cmd.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        MessageBox.Show("data inserted");
        con.Close();
        con.Dispose();
    }

谁能告诉我如何解决这个问题?

【问题讨论】:

  • 此代码应在第二个循环中引发异常。如果不先清除集合,则不能使用相同的参数名称再次调用 AddWithValue
  • 你为什么要这样做两次SqlConnection con = new SqlConnection(); 还应该将所有 Sql 对象包装在 using(){} 周围,并将 for 循环放在 using 或将 forloop 分离到单独的方法等中。 .
  • 如果你想要一个简单的方法,例如使用执行 sql Insert 并解析参数,我将发布一个简单的方法,你可以使用它比你现在做的更干净
  • Insert statement look like your error usp_InsertData 指定了太多参数是什么意思。` 非常不言自明,这意味着如果您有 26 个值,例如您正在传递,但存储的 proc 预计为 25...您'向存储过程传递了太多参数
  • 正如@MethodMan 所说,存储过程的声明并不期望有这么多参数。您可以添加 sp 的第一行(只是预期的参数列表)吗?

标签: c# .net sql-server stored-procedures datatable


【解决方案1】:

您可以使这变得更简单并且性能更好。与其通过痛苦的行来插入行,不如使用表值参数。您将创建自己的自定义表类型以匹配您要插入的列的类型。然后,您只需调用一个过程并将整个数据集作为一个参数传递,而不是所有这些迭代。

https://msdn.microsoft.com/en-us/library/bb675163%28v=vs.110%29.aspx https://msdn.microsoft.com/en-us/library/bb510489.aspx

【讨论】:

    【解决方案2】:

    您的代码在到达第二个循环时会引发异常,因为命令的参数集合已经填充了参数名称,并且再次调用具有相同名称的 AddWithValue 会引发异常。

    您可以在每个循环中调用Parameters.Clear() 方法,但更好的解决方案是在进入循环之前创建所有参数,然后在循环内设置当前行的值而不重新创建参数列表。

    String strConnString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
    using(SqlConnection con = new SqlConnection(strConnString))
    using(SqlCommand cmd = new SqlCommand("usp_InsertData", con))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        con.Open();
    
        cmd.Parameters.Add("@FirstIssue", SqlDbType.NVarChar);
        .... add the other parameters specifying the correct datatype .....
    
        for (int i = 1; i < dt.Rows.Count; i++)
        {
            cmd.Parameters["@FirstIssue"].Value = dt.Rows[i][0].ToString());
            ... other parameters values follows here ....
    
            // If you don't use the exception don't catch it....
            cmd.ExecuteNonQuery();
        }
    }
    

    还要注意,像连接和命令这样的一次性对象应该在 using 块内创建,以确保在出现异常时也能正确关闭和处理

    【讨论】:

    • 很好的解释@Steve,尤其是在 Parameters.Clear +1 中,您可能想向 OP 解释为什么最好使用 using 而不是显式调用 close 和 dispose
    【解决方案3】:

    您正在为每个循环的参数列表添加一个具有相同键的参数。

    在循环末尾添加cmd.Parameters.Clear()语句,在下一个循环开始之前清除参数,然后它应该可以工作了。

    顺便说一句,您的代码中存在很多性能问题。

    【讨论】:

    • 1) 您可以在循环外创建参数,然后在循环内分配值。 2)您没有清除或破坏 cmd 对象。 3)如果你可以修改存储过程,你可以修改它以接受整个数据表,而不是一次发送一行,如果数据表中有数百万行,这将成为应用程序的开销。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多