【问题标题】:The variable name '@Personnel_Number' has already been declared. Variable names must be unique within a query batch or stored procedure变量名称“@Personnel_Number”已被声明。变量名称在查询批处理或存储过程中必须是唯一的
【发布时间】:2020-02-01 19:07:11
【问题描述】:

我试图根据 Personal_No 显示员工姓名,但在这样做时出现错误

变量名称“@Personnel_Number”已被声明。变量名称在查询批处理或存储过程中必须是唯一的

我的代码:

protected void txtEmployeeNumber_TextChanged(object sender, EventArgs e)
{
    string EmployeeNo = "";
    string constring = ConfigurationManager.ConnectionStrings["SQLDBConnection"].ConnectionString;

    SqlConnection con = new SqlConnection(constring);
    SqlCommand cmd = new SqlCommand("select Employee_Name from [138.201.225.134].[iProfile].[dbo].[tbl_Employee] WHERE Personnel_Number= @Personnel_Number", con);
    cmd.CommandType = CommandType.Text;

    foreach (GridViewRow row in grdRegister.Rows)
    {
        if (row.RowType == DataControlRowType.DataRow)
        {
            EmployeeNo = (row.Cells[1].FindControl("txtEmployeeNumber") as TextBox).Text;
        }
        cmd.Parameters.AddWithValue("@Personnel_Number", EmployeeNo);

        con.Open();
        cmd.ExecuteNonQuery();
        con.Close();

        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataTable dt = new DataTable();
        da.Fill(dt);

        if (dt.Rows.Count > 0)
        {
            (row.Cells[2].FindControl("txtEmployeeName1") as TextBox).Text = dt.Rows[0]["Employee_Name"].ToString();
        }
    }
}

如果我尝试保留 (row.Cells[2].FindControl("txtEmployeeName1") as TextBox).Text = dt.Rows[0]["Employee_Name"].ToString();在 foreach 循环之外,然后在行上发生错误

请指导我应该在此代码中更改什么 我在 cmd.ExecuteNonQuery() 上遇到错误;而我的循环第二次运行。 我的文本框在网格视图内

【问题讨论】:

  • 有一个循环多次添加@Personnel_Number....正如错误所说...将其全部移入循环中。
  • 是的,而循环运行第二次出现错误,但我该如何解决?即使我不能将 executenonqury() 放在循环之外
  • SqlCommand cmd = ... 放在循环中
  • cmd.Parameters.Clear() 在循环的开头

标签: c# asp.net


【解决方案1】:

您可以在每次迭代结束时使用Clear 方法。 Try.like:

cmd.Parameters.Clear(); <--Add it at the end of loop

或者,您可以将初始化 SQlCOMmand 的代码放在 for 循环中,这样您将始终拥有一个新参数。比如:

foreach (GridViewRow row in grdRegister.Rows)
{
  SqlCommand cmd = new SqlCommand("select Employee_Name from [138.201.225.134].[iProfile].[dbo].[tbl_Employee] WHERE Personnel_Number= @Personnel_Number", con);
  cmd.CommandType = CommandType.Text;
  ....

【讨论】:

  • 我已经尝试过这个 cmd.Parameters.Clear();但它仍然显示
【解决方案2】:

在循环内实例化命令:

    protected void txtEmployeeNumber_TextChanged(object sender, EventArgs e)
    {
        string EmployeeNo = "";
        string constring = ConfigurationManager.ConnectionStrings["SQLDBConnection"].ConnectionString;
        SqlConnection con = new SqlConnection(constring);

        foreach (GridViewRow row in grdRegister.Rows)
        {
            if (row.RowType == DataControlRowType.DataRow)
            {
                EmployeeNo = (row.Cells[1].FindControl("txtEmployeeNumber") as TextBox).Text;
            }

            SqlCommand cmd = new SqlCommand("select Employee_Name from [138.201.225.134].[iProfile].[dbo].[tbl_Employee] WHERE Personnel_Number= @Personnel_Number", con);
            cmd.CommandType = CommandType.Text;
            cmd.Parameters.AddWithValue("@Personnel_Number", EmployeeNo);
            con.Open();
            cmd.ExecuteNonQuery();
            con.Close();
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dt = new DataTable();
            da.Fill(dt);
            if (dt.Rows.Count > 0)
            {
                (row.Cells[2].FindControl("txtEmployeeName1") as TextBox).Text = dt.Rows[0]["Employee_Name"].ToString();
            }
        }
    }

【讨论】:

  • 此解决方案为每一行创建一个SqlCommand 对象,这可能会对性能产生负面影响。
  • @NitsPatel 我已经在我的回答中添加了对您做错了什么的描述,希望它可以帮助您理解问题。
【解决方案3】:

在进入循环之前添加参数,然后在循环每一行时更改值:

cmd.Parameters.Add(new SqlParameter("@Personnel_Number", SqlDbType.VarChar));

foreach (GridViewRow row in grdRegister.Rows)
{
     //get EmployeeNo code

     cmd.Parameters["@Personnel_Number"].Value = EmployeeNo;    

     //rest of your code
}

HTH

【讨论】:

  • 我喜欢你添加 SqlParameter 的方式,但我想知道你怎么知道它是字符串...
  • @bradbury9 我不知道,但我认为开发人员能够知道他们的数据类型并进行相应的分配!
【解决方案4】:

你做错了一些事情。

-- 更新:我也错了!感谢@Polyfun 为我解决了这个问题。

1) 您不应在文本框编辑事件中进行更新。

将您的代码移动到按钮上。每次输入字符都执行 SQL 查询不太好。

2) 您正在循环中搜索控件。

EmployeeNo = (row.Cells[1].FindControl("txtEmployeeNumber") as TextBox).Text;

在循环之外找到它 - 它将加快整个过程。

关于您的问题,您正在手动解析数据库响应。为什么?

尝试使用Dapper!它可以从数据库响应中自动构建原生 C# 对象!
如果您是using it right,它支持变量并提供对SQL injections 的保护。
这是一个documentation。 您也可以使用Dapper Extensions 以获得更好的体验。

我上面的答案有点正确,但是使用 Dapper 你不必控制在哪里添加参数以及在哪里删除它们。

以下是 Dapper 的示例:

var result = connection.Query<SomeClass>("select * from SomeTable where UserId = @userId", new { userId });

很简单吧?

【讨论】:

  • 让我们做一个解决方法,而不是让 OP 意识到错误的逻辑,以便他/她可以学习...
  • 1 是一个不好的建议 - 对于扩展,您应该最小化 SqlConnections 的范围,并根据 Microsoft 的建议依赖默认连接池:docs.microsoft.com/en-us/dotnet/api/…
  • @Polyfun 哦。不知道!谢谢你帮我解决这个问题。
  • 更新了我的帖子
  • @bradbury9 我想你是对的,但 OP 可以使用库来避免此类问题。为什么要重新发明轮子?
【解决方案5】:

如果循环内有Add()AddWithValue(),但SqlCommand 在循环外,则在第二次迭代时,它将尝试添加另一个具有相同参数名称的参数。

请注意,我会选择前者而不是后者,而你should consider stop using AddWithValue

您应该:

        cmd.Parameters.Add(new SqlParameter("@Personnel_Number", SqlDbType.[Your SQL Type]));
        foreach (GridViewRow row in grdRegister.Rows)
        {
            if (row.RowType == DataControlRowType.DataRow)
            {
                EmployeeNo = (row.Cells[1].FindControl("txtEmployeeNumber") as TextBox).Text;
            }
            cmd.Parameters["@Personnel_Number"].Value = EmployeeNo;
            con.Open();
            // rest of your loop
        }

        foreach (GridViewRow row in grdRegister.Rows)
        {
            if (row.RowType == DataControlRowType.DataRow)
            {
                EmployeeNo = (row.Cells[1].FindControl("txtEmployeeNumber") as TextBox).Text;
            }
            cmd.Parameters.AddWithValue("@Personnel_Number", EmployeeNo);
            con.Open();
            cmd.ExecuteNonQuery();
            cmd.Parameters.Clear();
            con.Close();
            // rest of your loop
        }

【讨论】:

    【解决方案6】:

    正如@apomene 所述,您可以通过在每次迭代开始时添加以下单行来解决您的问题,如下示例所示

    foreach (GridViewRow row in grdRegister.Rows)
    {
    cmd.Parameters.Clear();
    //Do rest of work
    }
    

    但是恕我直言,您不需要执行以下操作**

     con.Open();
     cmd.ExecuteNonQuery();
     con.Close();
    

    您可以简单地将命令传递给数据适配器,然后您将使用填充功能在数据表中获取数据

    【讨论】:

      猜你喜欢
      • 2015-05-26
      • 2019-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 2020-08-23
      相关资源
      最近更新 更多